diff --git a/CHANGELOG.md b/CHANGELOG.md index 11d38aa..c553551 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,207 @@ [TOC] +## [Version 18.1][v18.1] + +OEMCrypto V18.0 consisted of header files only. This release includes tests and +OPK. There have been minor API changes since v18.0, so the version number has +been bumped to 18.1 + +In general, new v18 OEMCrypto features have been implemented in the OPK; since +those have been covered already in the published v18 headers, they will not be +discussed in detail here. + +This OPK release includes OEMCrypto v18 changes outlined in the document "WV +Modular DRM Version 18.1 Delta". In addition, quite a few OPK-specific changes +have been added since the last release. Major changes are described in more +detail below in individual sections, followed by a consolidated list of minor +changes. + +### OEMCrypto Unit Tests + +The unit tests have been updated to test all v18.1 functionality. + +We have also refactored the unit tests into several files grouped by category. + +Previously, the unit tests modifed the `GTEST_FILTER` in the file +`oec_device_features.cpp` in order to skip tests of functionality. For example +keybox tests are skipped for devices that use Provisioning 4.0. We have begun +replacing the modification of the `GTEST_FILTER` with the GTest macro +`GTEST_SKIP`. Previously, skipped tests would not show up on the list of running +tests in stdout. Now, any skipped test will start to run, and then a message +will explain why it is being skipped. A list of skipped tests will be listed to +stdout at the end of the test run. + +The seed corpus for the oemcrypto fuzz tests has been updated using the updated +unit tests. + +### REE-side hooks + +In oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c, new ifdef checks have +been added in OEMCrypto_Initialize, OEMCrypto_Terminate, OEMCrypto_DecryptCENC, +and OEMCrypto_LoadLicense. Depending on the macros, liboemcrypto can be compiled +with hooks that execute before, after, or instead of the listed OEMCrypto +functions (or some combination of the three). If a hook macro is defined, the +default behavior is to call that hook function instead of calling into the TEE +-- to do both, at least one more macro must be defined. For more detail, see +GEN_oemcrypto_api.c directly. + +For example, defining the macro `OPK_PRE_HOOK_OEMCRYPTO_DECRYPTCENC` will +execute `OPK_PreHook_OEMCrypto_DecryptCENC()` instead of calling into the TEE. +The same arguments will be passed to this function, which needs a custom +implementation. One use case for this is custom decryption hardware that is +accessible from the REE and can accept opaque decryption key handles intended +for the TEE. The above macro can be used to execute the hook function instead of +calling the TEE, and the hook function can pass the key handle and encrypted +content to the decrypt hardware directly, bypassing the TEE. + +Another example is in `OEMCrypto_Initialize()`. Defining the macro +`OPK_PRE_HOOK_OEMCRYPTO_INITIALIZE` will execute a call to +`OPK_Prehook_OEMCrypto_Initialize()` instead of calling into the TEE. Defining +another macro `OPK_HOOK_AND_USE_TA_OEMCRYPTO_INITIALIZE` will include the call +to the TEE after the pre-hook. The implementer is free to define custom REE-side +initialization logic, and continue to let the TA finish its initialization as +well. + +One more use case: `OEMCrypto_LoadLicense()`. Some implementers have requested +the ability to call a custom function after LoadLicense() returns in order to +parse the license response and control output restrictions accordingly from the +REE (HDCP, watermarking, etc). To do this, define +`OPK_POST_HOOK_OEMCRYPTO_LOAD_LICENSE` and +`OPK_HOOK_AND_USE_TA_OEMCRYPTO_LOAD_LICENSE` at build time and provide +a function implementation for `OPK_Posthook_OEMCrypto_LoadLicense()`. The post +hook function will execute after `OEMCrypto_LoadLicense()` comes back from the +TEE and will use the same function arguments. + +If no macros are defined, there is no change to GEN_oemcrypto_api.c and all +OEMCrypto calls will be forwarded to the TEE without hooks. + +### Configuration macros + +Previously, a platform-specific port needed to define hard coded values in the +implementation of `wtpi_config_interface.h`, as well as macro definitions in +`wtpi_config_macros.h`. These values defined which features were available in +the build, but they were difficult to modify for a new build, and it was often +unclear what configuration values were enabled for a particular build. + +These have been replaced with a single header file consisting of only macro +definitions. For a full list of these configuration macros with default values, +see oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h. + +Each platform-specific port needs to provide configuration values in a file +called `opk_config.h`. The OPK code looks for this file at compilation time. To +provide flexibility at build time, these macro definitions should be `#ifndef` +checked. This way, macros can be defined in the cflags to override the default +values if desired (eg build a version that only changes the provisioning method +by setting the `OPK_CONFIG_PROVISIONING_METHOD` macro in the cflags). The OP-TEE, +Trusty, and Linux reference ports all have `opk_config.h` files that can be used +as examples. + +As part of the OEMCrypto v18 changes, OEMCrypto_BuildInformation() now outputs +JSON-formatted text. If the OPK is built in debug mode, the build information +will also include all of the configuration macro values as a new JSON field. +The intent is to improve the debugging experience by providing as much +configuration information as possible. With the changes to +OEMCrypto_BuildInformation(), the `WTPI_BUILD_INFO` macro is no longer required. + +### OP-TEE port changes + +- Add implementations for provisioning 4.0 WTPI functions. This requires the + third party library open-dice. +- Pre-allocate crypto handles for DecryptCENC. Since this is + a performance-sensitive path, allocate once up front instead of per + DecryptCENC call. +- Reduce compiler warnings. +- Add support for RSA CAST receiver signing. +- Add QEMUv8 target. +- Move der_parse and related files into the wtpi_impl directory. +- Bugfix: Randomly generated ECC key in v17.1 sometimes was smaller than the + expected keysize. Fixed to include leading zeroes if needed. +- Bugfix: WPTI_GenerateRandomCertificateKeyPair() was implemented incorrectly. + It did not return the correct minimum size, used the wrong mbedtls key type, + and did not free allocated resources. Fixed all three issues. Please note + that on 64-bit targets, WPTI_GenerateRandomCertificateKeyPair() will exhaust + the default memory pool that OP-TEE uses for mbedtls. We suggest increasing + MPI_MEMPOOL_SIZE from 12k to 14k in optee_os/lib/libutee/tee_api_arith_mpi.c + to avoid this. + +### Trusty port changes + +In v17.1, the Trusty port did not compile against the OPK. This has been fixed +in v18, with the code moved one directory deeper to a folder named `reference`. + +Implementers looking to create a port based on this reference code are +encouraged to copy the `reference` folder and modify it, instead of modifying +the existing code directly. + +The Trusty port still requires a full download of AOSP Trusty, and must be built +into the Trusty kernel as a user module. In the future we plan to support +standalone TA builds that can be compiled or sideloaded into Trusty OS. + +At this time, there is still no easy way to test builds of the Trusty port +without hardware. QEMU support is planned for a future release. + +### Linux testing port + +A new folder has been created under `oemcrypto/opk/ports` for an implementation +that can run on Linux. Please note that this is a testing-only insecure +implementation, as all code executes in the REE. + +The oemcrypto_unittests and wtpi_unittests applications are the same. The "TA" +is a Linux application that spins a while loop until it receives a message, then +executes that call. The transport interface between liboemcrypto and this fake +TA uses Linux shmem APIs to pass messages back and forth. + +Again, this is not to be used in any kind of production release. The fake TA is +only intended as an easier way to test the REE-TEE code path without a trusted +OS. + +### Other changes + +- Provisioning 4 WTPI functions moved to wtpi_provisioning_4_interface.h. Some + new functions added such as WTPI_GetSignedCsrPayload() +- Provisioning 4 WTPI tests improved to test correctness of BCC and CoseSign1 + payloads, but requires new third party library COSE-C to do so. +- WTPI unit tests can be skipped based on configuration values. Currently + provisioning 4 WTPI functions are skipped if the configured provisioning + method is different. +- Calling an OEMCrypto function with shared buffer arguments could fail if the + underlying buffer was larger than the available shared memory. This would + occur before reaching the TEE in the serialization code, and would return the + default OEMCrypto_ERROR_UNKNOWN_FAILURE error. Now it returns + OEMCrypto_ERROR_BUFFER_TOO_LARGE. +- Fixed a memory leak in the asymmetric key table management code, where key + handles were not freed at session termination. +- Fixed a bug in the serialization code, where `uint8_t iv[16]` parameters were + not passed correctly through to the TEE, eg in AES operations. A NULL input + would always show up as a valid pointer to the TEE. This is now fixed and NULL + inputs show up as NULL in the TEE. + +### Known bugs + +- In the OP-TEE port, WTPI unit tests that use randomly generated ECC keys + occasionally (1/100) fail. The exact cause is unknown, but it appears to be + due to an edge case in the implementation of + WPTI_GenerateRandomCertificateKeyPair(). +- The OPK does not support Cast Receiver functionality when using Provisioning + 4.0. +- The OPK does not yet support MediaCAS functionality. + +## [OPK Version 17.1.1][v17.1+opk-v17.1.1] + +This release fixes a flaw in the OPK code that could allow content that requires +HDCP 2 to output over a display connection that only supports HDCP 1. This bug +would only be triggered if the WTPI implementation reports the minor version +number of HDCP 1 connections. If your implementation of +`WTPI_CurrentHDCPCapability()` ever returns `HDCP_V1_0`, `HDCP_V1_1`, +`HDCP_V1_2`, `HDCP_V1_3`, or `HDCP_V1_4`, your device is vulnerable and you +should take this patch urgently. If your implementation of +`WTPI_CurrentHDCPCapability()` only ever returns `HDCP_V1` for HDCP 1 +connections or does not support HDCP 1, then your device is not affected. You +will not need to change your WTPI implementation to apply this patch. + +This release also fixes the value of `maximum_minor_version` in ODK. + ## [Version 17.1][v17.1] This release contains a major change to the build process for the OP-TEE port, @@ -163,3 +364,5 @@ Public release for OEMCrypto API and ODK library version 16.4. [v17+test-updates+opk]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17+test-updates+opk [v17+test-updates+opk+mk]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17+test-updates+opk+mk [v17.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1 +[v17.1+opk-v17.1.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1+opk-v17.1.1 +[v18.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.1 diff --git a/README b/README index 05e80a6..40facf9 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ This is the OEMCrypto git repository. It is visible to Widevine partners, and contains documentation for OEMCrypto, -as well as unit tests and reference code. +as well as unit tests and reference code. Several versions of OEMCrypto are available on different branches. This is the only file on the master branch. Please use the git checkout command to work diff --git a/linux/src/log.cpp b/linux/src/log.cpp index 7cf45fc..14d0d8d 100644 --- a/linux/src/log.cpp +++ b/linux/src/log.cpp @@ -25,14 +25,14 @@ void InitLogging() { // set by jenkins (http://go/wvbuild), so that we have more details when the // build breaks. const char* verbose_env = getenv("VERBOSE_LOG"); - if (verbose_env && !strncmp(verbose_env, "yes", 3) ) { + if (verbose_env && !strncmp(verbose_env, "yes", 3)) { g_cutoff = CDM_LOG_VERBOSE; } } void Log(const char* file, const char* function, int line, LogPriority level, const char* fmt, ...) { - const char* severities[] = { "ERROR", "WARN", "INFO", "DEBUG", "VERBOSE" }; + const char* severities[] = {"ERROR", "WARN", "INFO", "DEBUG", "VERBOSE"}; if (level >= static_cast(sizeof(severities) / sizeof(*severities))) { fprintf(kOutputFile, "[FATAL:%s(%d):%s] Invalid log priority level: %d\n", @@ -41,12 +41,11 @@ void Log(const char* file, const char* function, int line, LogPriority level, } if (level > g_cutoff) return; - // Strip off the the leading "../" that clutters the logs. - const char * up_dir = "../"; + // Strip off the leading "../" that clutters the logs. + const char* up_dir = "../"; const size_t up_dir_size = strlen(up_dir); while (strncmp(up_dir, file, up_dir_size) == 0) file += up_dir_size; - fprintf(kOutputFile, "[%s:%s(%d):%s] ", severities[level], file, line, function); diff --git a/oem_certificate_generator/README.md b/oem_certificate_generator/README.md index 92b4c5e..a9fd483 100644 --- a/oem_certificate_generator/README.md +++ b/oem_certificate_generator/README.md @@ -16,7 +16,7 @@ OEM certificate generation tool ## Usage -Run `python oem_certificate.py --help` to see available commands. +Run `python3 oem_certificate.py --help` to see available commands. The arguments can be partially or fully loaded from a configuration file, for example, if file "location.cfg" is, @@ -32,14 +32,14 @@ example, if file "location.cfg" is, A command of ```bash - python oem_certificate.py generate_csr @location.cfg -CN TestDevice1 \ + python3 oem_certificate.py generate_csr @location.cfg -CN TestDevice1 \ --output_csr_file=csr.pem --output_private_key_file=key.der ``` is equivalent to ```bash - python oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA \ + python3 oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA \ -L=Kirkland -O='Some Company' -OU='Some Unit' --output_csr_file=csr.pem \ --output_private_key_file=key.der. ``` diff --git a/oem_certificate_generator/oem_certificate.py b/oem_certificate_generator/oem_certificate.py index 71e7789..cf4e9e1 100755 --- a/oem_certificate_generator/oem_certificate.py +++ b/oem_certificate_generator/oem_certificate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # Copyright 2017 Google LLC. All Rights Reserved. """OEM certificate generation tool. @@ -26,10 +26,10 @@ example, if file "location.cfg" is, -OU=Some Unit A command of - "python oem_certificate.py generate_csr @location.cfg -CN TestDevice1 " + "python3 oem_certificate.py generate_csr @location.cfg -CN TestDevice1 " "--output_csr_file=csr.pem --output_private_key_file=key.der", is equivalent to - "python oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA " + "python3 oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA " "-L=Kirkland -O='Some Company' -OU='Some Unit' --output_csr_file=csr.pem " "--output_private_key_file=key.der". diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index d34b309..87eb1f6 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -3,7 +3,7 @@ // License Agreement. /** - * @mainpage OEMCrypto API v17 + * @mainpage OEMCrypto API v18.1 * * OEMCrypto is the low level library implemented by the OEM to provide key and * content protection, usually in a separate secure memory or process space. The @@ -121,7 +121,7 @@ * application or the license server. * * @defgroup drm_cert DRM Certificate Provisioning API - * This section of functions are used to provision the device with an DRM + * This section of functions are used to provision the device with a DRM * certificate. This certificate is obtained by a device in the field from a * Google/Widevine provisioning server, or from a third party server running the * Google/Widevine provisioning server SDK. Since the DRM certificate may be @@ -135,6 +135,13 @@ * The usage table is used to store license usage and allows a persistent * license to be reloaded. * + * @defgroup entitled Entitlement License API + * + * [Entitlement licensing](../../index#entitlement) is a way to provide access + * to content keys that may be stored elsewhere, such as in the content itself. + * This can be used to implement content key rotation without requiring new + * licenses, or access to multiple pieces of content with a single license. + * * @defgroup test_verify Test and Verification API * Functions that are designed to help test OEMCrypto and the device. They are * not used during normal operation. Some functions, like those that test the @@ -376,6 +383,20 @@ typedef enum OEMCryptoCipherMode { OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_ECB, } OEMCryptoCipherMode; +/** + * This is a list of valid algorithms for OEMCrypto_Generic_* functions. + * Some are valid for encryption/decryption, and some for signing/verifying. + */ +typedef enum OEMCrypto_Algorithm { + OEMCrypto_AES_CBC_128_NO_PADDING = 0, + OEMCrypto_HMAC_SHA256 = 1, + OEMCrypto_Algorithm_MaxValue = 1, +} OEMCrypto_Algorithm; + +/// @} + +/// @addtogroup entitled +/// @{ /** * Contains encrypted content key data for loading into the sessions keytable. * The content key data is encrypted using AES-256-CBC encryption, with PKCS#7 @@ -399,46 +420,6 @@ typedef struct { OEMCryptoCipherMode cipher_mode; } OEMCrypto_EntitledContentKeyObject; -/** - * This is a list of valid algorithms for OEMCrypto_Generic_* functions. - * Some are valid for encryption/decryption, and some for signing/verifying. - */ -typedef enum OEMCrypto_Algorithm { - OEMCrypto_AES_CBC_128_NO_PADDING = 0, - OEMCrypto_HMAC_SHA256 = 1, - OEMCrypto_Algorithm_MaxValue = 1, -} OEMCrypto_Algorithm; - -/// @} - -/// @addtogroup keyladder -/// @{ -/** - * This structure is being deprecated. It is only used for legacy licenses. - * Points to the relevant fields for renewing a content key. The fields are - * extracted from the License Renewal Response message offered to - * OEMCrypto_RefreshKeys(). Each field points to one of the components of - * the key. - - * @param key_id: the unique id of this key. - * @param key_control_iv: the IV for performing AES-128-CBC decryption of the - * key_control field. 16 bytes. - * @param key_control: the key control block. It is encrypted (AES-128-CBC) with - * the content key from the key_data field. 16 bytes. - * - * The key_data is unchanged from the original OEMCrypto_LoadKeys() call. Some - * Key Control Block fields, especially those related to key lifetime, may - * change. - * - * The memory for the OEMCrypto_KeyRefreshObject fields is allocated and freed - * by the caller of OEMCrypto_RefreshKeys(). - */ -typedef struct { - OEMCrypto_Substring key_id; - OEMCrypto_Substring key_control_iv; - OEMCrypto_Substring key_control; -} OEMCrypto_KeyRefreshObject; - /// @} /// @addtogroup usage_table @@ -543,6 +524,16 @@ typedef enum OEMCrypto_WatermarkingSupport { OEMCrypto_WatermarkingAlwaysOn = 3, } OEMCrypto_WatermarkingSupport; +/** + Return value for OEMCrypto_GetSignatureHashAlgorithm(). + */ +typedef enum OEMCrypto_SignatureHashAlgorithm { + OEMCrypto_SHA1 = 0, + OEMCrypto_SHA2_256 = 1, + OEMCrypto_SHA2_384 = 2, + OEMCrypto_SHA2_512 = 3, +} OEMCrypto_SignatureHashAlgorithm; + /** * Flags indicating public/private key types supported. */ @@ -574,6 +565,13 @@ typedef enum OEMCrypto_WatermarkingSupport { /** * Obfuscation Renames. + * + * The function signatures of each oecc obfuscated name should remain static + * across multiple versions. When we want to change the function signature of a + * function, we will give the new signature a new oecc number and keep the + * original oecc name with the original function signature. This allows us to + * maintain backwards compatibility when the CDM loads an older version of + * liboemcrypto.so using dlopen. */ // clang-format off #define OEMCrypto_Initialize _oecc01 @@ -608,10 +606,10 @@ typedef enum OEMCrypto_WatermarkingSupport { #define OEMCrypto_DeriveKeysFromSessionKey _oecc21 #define OEMCrypto_APIVersion _oecc22 #define OEMCrypto_SecurityLevel_V16 _oecc23 -#define OEMCrypto_Generic_Encrypt _oecc24 -#define OEMCrypto_Generic_Decrypt _oecc25 -#define OEMCrypto_Generic_Sign _oecc26 -#define OEMCrypto_Generic_Verify _oecc27 +#define OEMCrypto_Generic_Encrypt_V17 _oecc24 +#define OEMCrypto_Generic_Decrypt_V17 _oecc25 +#define OEMCrypto_Generic_Sign_V17 _oecc26 +#define OEMCrypto_Generic_Verify_V17 _oecc27 #define OEMCrypto_GetHDCPCapability_V9 _oecc28 #define OEMCrypto_SupportsUsageTable _oecc29 #define OEMCrypto_UpdateUsageTable _oecc30 @@ -678,7 +676,7 @@ typedef enum OEMCrypto_WatermarkingSupport { #define OEMCrypto_LoadProvisioning _oecc102 #define OEMCrypto_LoadOEMPrivateKey _oecc103 #define OEMCrypto_GetOEMPublicCertificate _oecc104 -#define OEMCrypto_DecryptCENC _oecc105 +#define OEMCrypto_DecryptCENC_V17 _oecc105 #define OEMCrypto_LoadDRMPrivateKey _oecc107 #define OEMCrypto_MinorAPIVersion _oecc108 #define OEMCrypto_AllocateSecureBuffer _oecc109 @@ -702,6 +700,18 @@ typedef enum OEMCrypto_WatermarkingSupport { #define OEMCrypto_ReuseUsageEntry _oecc127 #define OEMCrypto_GetDTCP2Capability _oecc128 #define OEMCrypto_GetWatermarkingSupport _oecc129 +#define OEMCrypto_GetOEMKeyToken _oecc130 +#define OEMCrypto_GetDeviceInformation _oecc131 +#define OEMCrypto_SetMaxAPIVersion _oecc132 +#define OEMCrypto_GetKeyHandle _oecc133 +#define OEMCrypto_DecryptCENC _oecc134 +#define OEMCrypto_Generic_Encrypt _oecc135 +#define OEMCrypto_Generic_Decrypt _oecc136 +#define OEMCrypto_Generic_Sign _oecc137 +#define OEMCrypto_Generic_Verify _oecc138 +#define OEMCrypto_GetSignatureHashAlgorithm _oecc139 +#define OEMCrypto_EnterTestMode _oecc140 +#define OEMCrypto_GetDeviceSignedCsrPayload _oecc141 // clang-format on /// @addtogroup initcontrol @@ -767,6 +777,30 @@ OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, */ OEMCryptoResult OEMCrypto_Initialize(void); +/** + * Specify the maximum OEMCrypto API version supported by the CDM layer above + * OEMCrypto. If OEMCrypto can support multiple versions then it must restrict + * itself to this version number. If OEMCrypto only supports one version, then + * it may ignore this function and return + * ERROR_NOT_IMPLEMENTED. OEMCrypto_SetMaxAPIVersion will be called after + * OEMCrypto_Initialize() and before any other functions. + * + * @param[in] max_version: the maximum version of OEMCrypto supported by CDM + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED function not implemented + * @retval other any other error + * + * @threading + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * @version + * This method is new in API version 18. + */ +OEMCryptoResult OEMCrypto_SetMaxAPIVersion(uint32_t max_version); + /** * Closes the crypto operation and releases all related resources. * @@ -915,39 +949,6 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); */ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); -/** - * This method creates an entitled key session. - * - * @param[in] oec_session: handle for the OEMCrypto session to be associated - * with the created entitled key session. - * @param[out] key_session: id of the created entitled key session. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_SESSION - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_CreateEntitledKeySession( - OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session); - -/** - * This method which removes an entitled key session. - * - * @param[in] key_session: id of the entitled key session to be removed. - * - * Returns: - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( - OEMCrypto_SESSION key_session); - /** * Generates three secondary keys, mac_key[server], mac_key[client], and * encrypt_key, for handling signing and content key decryption under the @@ -959,7 +960,7 @@ OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( * the mac_key_context and stores it in the mac_keys -- the first two cycles * generate the mac_key[server] and the second two cycles generate the * mac_key[client]. These two keys will be stored until the next call to - * OEMCrypto_LoadKeys(). The device key from the keybox is used as the key + * OEMCrypto_LoadLicense(). The device key from the keybox is used as the key * for the AES-128-CMAC. * * @param[in] session: handle for the session to be used. @@ -1032,9 +1033,13 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys( * ECC private key and the derivation_key. See the document "OEMCrypto * Elliptic Curve Support" for details. * - * Once the enc_key and mac_keys have been generated, all calls to LoadKeys - * or LoadLicense proceed in the same manner for license requests using RSA - * or using a Widevine keybox token. + * Once the enc_key and mac_keys have been generated, all calls to + * OEMCrypto_LoadLicense() proceed in the same manner for license requests using + * RSA or using a Widevine keybox token. + * + * This function is also used to derive keys before processing a Cast + * Certificate provisioning response in OEMCrypto_LoadProvisioning(). + * See [Cast Receiver](../../cast) for more details. * * @verification * If the RSA key's allowed_schemes is not kSign_RSASSA_PSS, then no keys are @@ -1240,14 +1245,14 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( * for license request signing under the license server protocol for CENC. * * The key used for signing should be the mac_key[client] that was generated - * for this session or loaded for this session by OEMCrypto_LoadKeys(), - * OEMCrypto_LoadLicense(), or OEMCrypto_LoadUsageEntry(). + * for this session or loaded for this session by + * OEMCrypto_LoadLicense() or OEMCrypto_LoadUsageEntry(). * * Refer to the Signing Messages Sent to a Server section above for more * details. * * If a usage entry has been loaded, but keys have not been loaded through - * OEMCrypto_LoadKeys(), then the derived mac keys and the keys in the usage + * OEMCrypto_LoadLicense(), then the derived mac keys and the keys in the usage * entry may be different. In this case, the mac keys specified in the usage * entry should be used. * @@ -1296,253 +1301,6 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); -/** - * Install a set of keys for performing decryption in the current session. - * This function will be deprecated and will only be used for legacy license - * from a license server that does not yet support the v16 interface. - * - * The relevant fields have been extracted from the License Response protocol - * message, but the entire message and associated signature are provided so - * the message can be verified (using HMAC-SHA256 with the derived - * mac_key[server]). If the signature verification fails, ignore all other - * arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the - * keys to the session context. - * - * The keys will be decrypted using the current encrypt_key (AES-128-CBC) and - * the IV given in the KeyObject. Each key control block will be decrypted - * using the first 128 bits of the corresponding content key (AES-128-CBC) - * and the IV given in the KeyObject. - * - * If its length is not zero, enc_mac_keys will be used to create new - * mac_keys. After all keys have been decrypted and validated, the new mac_keys - * are decrypted with the current encrypt_key and the offered IV. The new - * mac_keys replaces the current mac_keys for future calls to - * OEMCrypto_RefreshKeys(). The first 256 bits of the mac_keys become the - * mac_key[server] and the following 256 bits of the mac_keys become the - * mac_key[client]. Some servers will pad the encrypted mac keys to 80 bytes. If - * there are more than 64 bytes in the enc_mac_keys string, the remaining bytes - * shall be ignored by OEMCrypto. - * - * The mac_key and encrypt_key were generated and stored by the previous call - * to OEMCrypto_GenerateDerivedKeys() or - * OEMCrypto_DeriveKeysFromSessionKey(). The nonce was generated and stored - * in the session's nonce_values by the previous call to - * OEMCrypto_GenerateNonce(). - * - * This session's elapsed time clock is started at 0. The clock will be used - * in OEMCrypto_DecryptCENC(). - * - * NOTE: The calling software must have previously established the mac_keys - * and encrypt_key with a call to OEMCrypto_DeriveKeysFromSessionKey(). - * - * Refer to the Verification of Messages from a Server section above for more - * details. - * - * If the parameter license_type is OEMCrypto_ContentLicense, then the fields - * key_id and key_data in an OEMCrypto_KeyObject are loaded in to the - * content_key_id and content_key_data fields of the key table entry. In this - * case, entitlement key ids and entitlement key data is left blank. - * - * If the parameter license_type is OEMCrypto_EntitlementLicense, then the - * fields key_id and key_data in an OEMCrypto_KeyObject are loaded in to the - * entitlement_key_id and entitlement_key_data fields of the key table entry. - * In this case, content key ids and content key data will be loaded later - * with a call to OEMCrypto_LoadEntitledContentKeys(). - * - * OEMCrypto may assume that the key_id_length is at most 16. However, - * OEMCrypto shall correctly handle key id lengths from 1 to 16 bytes. - * - * OEMCrypto shall handle at least 20 keys per session. This allows a single - * license to contain separate keys for 3 key rotations (previous interval, - * current interval, next interval) times 4 content keys (audio, SD, HD, UHD) - * plus up to 8 keys for watermarks. - * - * After a call to OEMCrypto_LoadKeys(), oemcrypto should clear the encrypt_key - * for the session. - * - * @verification - * The following checks should be performed. If any check fails, an error is - * returned, and none of the keys are loaded. - * 1. The signature of the message shall be computed, and the API shall - * verify the computed signature matches the signature passed in. If - * not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. The signature - * verification shall use a constant-time algorithm (a signature - * mismatch will always take the same time as a successful comparison). - * 2. If there already is a license loaded into this session, return - * OEMCrypto_ERROR_LICENSE_RELOAD. - * 3. The enc_mac_keys substring must either have zero length, or satisfy - * the range check. I.e. (offset < message_length) && (offset + length - * <= message_length) && (offset <= offset + length), and offset + length - * does not cause an integer overflow. If it does not have zero length, - * then enc_mac_keys_iv must not have zero length, and must also satisfy - * the range check. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. If - * the length is zero, then OEMCrypto may assume that the offset is also - * zero. - * 4. The API shall verify that each substring in each KeyObject points to - * a location in the message. I.e. (offset < message_length) && - * (offset + length <= message_length) && (offset <= offset + length), - * and offset + length does not cause an integer overflow, for each of - * key_id, key_data_iv, key_data, key_control_iv, key_control. If not, - * return OEMCrypto_ERROR_INVALID_CONTEXT. - * 5. Each key's control block, after decryption, shall have a valid - * verification field. If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * 6. If any key control block has the Nonce_Enabled bit set, that key's - * Nonce field shall match a nonce in the cache. If not, return - * OEMCrypto_ERROR_INVALID_NONCE. If there is a match, remove that - * nonce from the cache. Note that all the key control blocks in a - * particular call shall have the same nonce value. - * 7. If any key control block has the Require_AntiRollback_Hardware bit - * set, and the device does not protect the usage table from rollback, - * then do not load the keys and return OEMCrypto_ERROR_UNKNOWN_FAILURE. - * 8. If the key control block has a nonzero Replay_Control, then the - * verification described below is also performed. - * 9. If the key control block has the bit SRMVersionRequired is set, then - * the verification described below is also performed. If the SRM - * requirement is not met, then the key control block's HDCP_Version - * will be changed to 0xF - local display only. - * 10. If key_array_length == 0, then return - * OEMCrypto_ERROR_INVALID_CONTEXT. - * 11. If this session is associated with a usage table entry, and that - * entry is marked as "inactive" (either kInactiveUsed or - * kInactiveUnused), then the keys are not loaded, and the error - * OEMCrypto_ERROR_LICENSE_INACTIVE is returned. - * 12. The data in enc_mac_keys_iv is not identical to the 16 bytes before - * enc_mac_keys. If it is, return OEMCrypto_ERROR_INVALID_CONTEXT. - * Usage Table and Provider Session Token (pst) - * If a key control block has a nonzero value for Replay_Control, then all - * keys in this license will have the same value for Replay_Control. In this - * case, the following additional checks are performed. - * - The substring pst must have nonzero length and must satisfy the range - * check described above. If not, return - * OEMCrypto_ERROR_INVALID_CONTEXT. - * - The session must be associated with a usage table entry, either - * created via OEMCrypto_CreateNewUsageEntry() or loaded via - * OEMCrypto_LoadUsageEntry(). - * - If Replay_Control is 1 = Nonce_Required, then OEMCrypto will perform a - * nonce check as described above. OEMCrypto will verify that the - * usage entry is newly created with OEMCrypto_CreateNewUsageEntry(). If - * an existing entry was reloaded, an error - * OEMCrypto_ERROR_INVALID_CONTEXT is returned and no keys are loaded. - * OEMCrypto will then copy the pst and the mac keys to the usage entry, - * and set the status to Unused. This Replay_Control prevents the - * license from being loaded more than once, and will be used for online - * streaming. - * - If Replay_Control is 2 = "Require existing Session Usage table entry - * or Nonce", then OEMCrypto will behave slightly differently on the - * first call to LoadKeys for this license. - * * If the usage entry was created with OEMCrypto_CreateNewUsageEntry() - * for this session, then OEMCrypto will verify the nonce for each - * key. OEMCrypto will copy the pst and mac keys to the usage - * entry. The license received time of the entry will be updated - * to the current time, and the status will be set to Unused. - * * If the usage entry was loaded with OEMCrypto_LoadUsageEntry() for - * this session, then OEMCrypto will NOT verify the nonce for each - * key. Instead, it will verify that the pst passed in matches - * that in the entry. Also, the entry's mac keys will be verified - * against the current session's mac keys. This allows an offline - * license to be reloaded but maintain continuity of the playback - * times from one session to the next. - * * If the nonce is not valid and a usage entry was not loaded, the - * return error is OEMCrypto_ERROR_INVALID_NONCE. - * * If the loaded usage entry has a pst that does not match, - * OEMCrypto returns the error OEMCrypto_ERROR_WRONG_PST. - * * If the loaded usage entry has mac keys that do not match the - * license, OEMCrypto returns the error OEMCrypto_ERROR_WRONG_KEYS. - * Note: If LoadKeys updates the mac keys, then the new updated mac keys will - * be used with the Usage Entry -- i.e. the new keys are stored in the - * usage table when creating a new entry, or the new keys are verified - * against those in the usage table if there is an existing entry. If - * LoadKeys does not update the mac keys, the existing session mac keys are - * used. - * - * Sessions that are associated with an entry will need to be able to update - * and verify the status of the entry, and the time stamps in the entry. - * - * Devices that do not support the Usage Table will return - * OEMCrypto_ERROR_INVALID_CONTEXT if the Replay_Control is nonzero. - * - * Timer Update - * After verification, the session's clock and timer values are updated by - * calling the function ODK_InitializeV15Values as described in the document - * "Widevine Core Message Serialization". - * - * SRM Restriction Data - * - * If any key control block has the flag SRMVersionRequired set, then the - * following verification is also performed. - * - * 1. The substring srm_restriction_data must have nonzero length and must - * satisfy the range check described above. If not, return - * OEMCrypto_ERROR_INVALID_CONTEXT. - * 2. The first 8 bytes of srm_restriction_data must match the string - * "HDCPDATA". If not, return OEMCrypto_ERROR_INVALID_CONTEXT. - * 3. The next 4 bytes of srm_restriction_data will be converted from - * network byte order. If the current SRM installed on the device has a - * version number less than this, then the SRM requirement is not met. - * If the device does not support SRM files, or OEMCrypto cannot - * determine the current SRM version number, then the SRM requirement is - * not met. - * Note: if the current SRM version requirement is not met, LoadKeys will - * still succeed and the keys will be loaded. However, those keys with the - * SRMVersionRequired bit set will have their HDCP_Version increased to 0xF - - * local display only. Any future call to SelectKey for these keys while - * there is an external display will return OEMCrypto_ERROR_INSUFFICIENT_HDCP - * at that time. - * - * @param[in] session: crypto session identifier. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] signature: pointer to memory containing the signature. - * @param[in] signature_length: length of the signature, in bytes. - * @param[in] enc_mac_keys_iv: IV for decrypting new mac_key. Size is 128 bits. - * @param[in] enc_mac_keys: encrypted mac_keys for generating new mac_keys. - * Size is 512 bits. - * @param[in] key_array_length: number of keys present. - * @param[in] key_array: set of keys to be installed. - * @param[in] pst: the Provider Session Token. - * @param[in] srm_restriction_data: optional data specifying the minimum SRM - * version. - * @param[in] license_type: specifies if the license contains content keys or - * entitlement keys. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NO_DEVICE_KEY - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_SIGNATURE_FAILURE - * @retval OEMCrypto_ERROR_INVALID_NONCE - * @retval OEMCrypto_ERROR_TOO_MANY_KEYS - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * @retval OEMCrypto_ERROR_LICENSE_RELOAD - * - * @buffer_size - * OEMCrypto shall support message sizes as described in the section - * OEMCrypto_ResourceRatingTier(). - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method changed in API version 16. - */ -OEMCryptoResult OEMCrypto_LoadKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t key_array_length, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type); - /** * Install a set of keys for performing decryption in the current session. * @@ -1653,6 +1411,10 @@ OEMCryptoResult OEMCrypto_LoadKeys( * OEMCrypto_ERROR_LICENSE_INACTIVE is returned. * 24. The data in enc_mac_keys_iv is not identical to the 16 bytes before * enc_mac_keys. If it is, return OEMCrypto_ERROR_INVALID_CONTEXT. + * 25. IF ODK_ParseLicense returns ODK_TIMER_EXPIRED, return + * OEMCrypto_ERROR_KEY_EXPIRED. If ODK_ParseLicense returns ODK_SET_TIMER + * or ODK_DISABLE_TIMER, the playback timer has started and OEMCrypto + * should treat this as if a Decrypt call has been made. * * Usage Table and Provider Session Token (pst) * The function ODK_ParseLicense takes several parameters that may need more @@ -1700,7 +1462,7 @@ OEMCryptoResult OEMCrypto_LoadKeys( * more than once, and will be used for online streaming. * - If Replay_Control is 2 = "Require existing Session Usage table entry * or Nonce", then OEMCrypto will behave slightly differently on the - * first call to LoadKeys for this license. + * first call to LoadLicense for this license. * * If the usage entry was created with OEMCrypto_CreateNewUsageEntry() * for this session, then OEMCrypto will verify the nonce for each * key. OEMCrypto will copy the pst and mac keys to the usage @@ -1719,11 +1481,11 @@ OEMCryptoResult OEMCrypto_LoadKeys( * OEMCrypto returns the error OEMCrypto_ERROR_WRONG_PST. * * If the loaded usage entry has mac keys that do not match the * license, OEMCrypto returns the error OEMCrypto_ERROR_WRONG_KEYS. - * Note: If LoadKeys updates the mac keys, then the new updated mac keys will + * Note: If LoadLicense updates the mac keys, then the new updated mac keys will * be used with the Usage Entry -- i.e. the new keys are stored in the * usage table when creating a new entry, or the new keys are verified * against those in the usage table if there is an existing entry. If - * LoadKeys does not update the mac keys, the existing session mac keys are + * LoadLicense does not update the mac keys, the existing session mac keys are * used. * Sessions that are associated with an entry will need to be able to update * and verify the status of the entry, and the time stamps in the entry. @@ -1743,7 +1505,7 @@ OEMCryptoResult OEMCrypto_LoadKeys( * If the device does not support SRM files, or OEMCrypto cannot * determine the current SRM version number, then the SRM requirement is * not met. - * Note: if the current SRM version requirement is not met, LoadKeys will + * Note: if the current SRM version requirement is not met, LoadLicense will * still succeed and the keys will be loaded. However, those keys with the * SRMVersionRequired bit set will have their HDCP_Version increased to 0xF - * local display only. Any future call to SelectKey for these keys while @@ -1771,6 +1533,7 @@ OEMCryptoResult OEMCrypto_LoadKeys( * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED * @retval OEMCrypto_ERROR_LICENSE_RELOAD + * @retval OEMCrypto_ERROR_KEY_EXPIRED * * @buffer_size * OEMCrypto shall support message sizes as described in the section @@ -1795,167 +1558,6 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, const uint8_t* signature, size_t signature_length); -/** - * Load content keys into a session which already has entitlement keys - * loaded. This function will only be called for a session after a call to - * OEMCrypto_LoadKeys() with the parameter type license_type equal to - * OEMCrypto_EntitlementLicense. This function may be called multiple times - * for the same session. - * - * If the session does not have license_type equal to - * OEMCrypto_EntitlementLicense, return OEMCrypto_ERROR_INVALID_CONTEXT and - * perform no work. - * - * For each key object in key_array, OEMCrypto shall look up the entry in the - * key table with the corresponding entitlement_key_id. - * - * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. - * 2. If the entry already has a content_key_id and content_key_data, that - * id and data are erased. - * 3. The content_key_id from the key_array is copied to the entry's - * content_key_id. - * 4. The content_key_data decrypted using the entitlement_key_data as a - * key for AES-256-CBC with an IV of content_key_data_iv. Notice that - * the entitlement key will be an AES 256 bit key. The clear content key - * data will be stored in the entry's content_key_data. - * Entries in the key table that do not correspond to anything in the - * key_array are not modified or removed. - * - * For devices that use a hardware key ladder, it may be more convenient to - * store the encrypted content key data in the key table, and decrypt it when - * the function SelectKey is called. - * - * @param[in] session: handle for the entitled key session to be used. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] key_array_length: number of keys present. - * @param[in] key_array: set of key updates. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_KEY_NOT_ENTITLED - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method changed in API version 17. - */ -OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array); - -/** - * NOTE: OEMCrypto_RefreshKeys() is only used to load a v15 license or renewal. - * Because there are no longer any active v15 servers, this function is only - * needed for devices that are upgraded to v17, not new devices. - * - * Updates the license clock values to allow playback to continue. This - * function is being deprecated and is only used for version v15 licenses -- - * i.e. offline license saved before an update or licenses from a server that - * has not update to the v16 license server SDK. - * - * OEMCrypto shall compute the signature of the message using - * mac_key[server], and shall verify the computed signature matches the - * signature passed in. If not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. The - * signature verification shall use a constant-time algorithm (a signature - * mismatch will always take the same time as a successful comparison). - * - * The key control from the first OEMCrypto_KeyRefreshObject in the key_array - * shall be extracted. If it is encrypted, as described below, it shall be - * decrypted. The duration from the key control shall be extracted and - * converted to host byte order. This duration shall be passed to the - * function ODK_RefreshV15Values as the parameter new_key_duration. - * - * If the KeyRefreshObject's key_control_iv has zero length, then the - * key_control is not encrypted. If the key_control_iv is specified, then - * key_control is encrypted with the first 128 bits of the corresponding - * content key. - * - * If the KeyRefreshObject's key_id has zero length, then it is an error for - * the key_control_iv to have nonzero length. OEMCrypto shall return an error - * of OEMCrypto_ERROR_INVALID_CONTEXT. - * - * If the session's license_type is OEMCrypto_ContentLicense, and the - * KeyRefreshObject's key_id is not null, then the entry in the keytable with - * the matching content_key_id is used. - * - * If the session's license_type is OEMCrypto_EntitlementLicense, and the - * KeyRefreshObject's key_id is not null, then the entry in the keytable with - * the matching entitlment_key_id is used. - * - * The function ODK_RefreshV15Values shall be called to update the clock - * values. See [Widevine Core Message Serialization](../../odk) for the - * documentation of the ODK library functions. - * - * If ODK_RefreshV15Values returns - * - * - ODK_SET_TIMER: Success. The timer should be reset to the specified - * timer value. - * - ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is - * allowed. - * - ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. - * - ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is - * rejected. Return this error - * - Any other error - OEMCrypto shall pass any other error up to the - * caller of OEMCrypto_RefreshKeys(). - * - * NOTE: OEMCrypto_LoadKeys() must be called first to load the keys into the - * session. - * - * @param[in] session: handle for the session to be used. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] signature: pointer to memory containing the signature. - * @param[in] signature_length: length of the signature, in bytes. - * @param[in] num_keys: number of keys present. - * @param[in] key_array: set of key updates. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NO_DEVICE_KEY - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_SIGNATURE_FAILURE - * @retval OEMCrypto_ERROR_INVALID_NONCE - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE - * @retval OEMCrypto_ERROR_NO_CONTENT_KEY - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * - * @buffer_size - * OEMCrypto shall support message sizes as described in the section - * OEMCrypto_ResourceRatingTier(). - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method changed in API version 16. - */ -OEMCryptoResult OEMCrypto_RefreshKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, size_t num_keys, - const OEMCrypto_KeyRefreshObject* key_array); - /** * Updates the clock values and resets the renewal timer for the current * session. @@ -1966,8 +1568,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys( * match, OEMCrypto returns OEMCrypto_ERROR_SIGNATURE_FAILURE. * * OEMCrypto shall verify that nonce_values.api_major_version is 16. If not, - * return the error OEMCrypto_ERROR_INVALID_CONTEXT. Legacy licenses will use - * the function OEMCrypto_RefreshKeys() instead of OEMCrypto_LoadRenewal(). + * return the error OEMCrypto_ERROR_INVALID_CONTEXT. * * If the signature passes, OEMCrypto shall use the function * ODK_ParseRenewal, as described in the document "Widevine Core Message @@ -2035,7 +1636,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, /** * Returns the decrypted key control block for the given content_key_id. This * function is for application developers to debug license server and key - * timelines. It only returns a key control block if LoadKeys was successful, + * timelines. It only returns a key control block if LoadLicense was successful, * otherwise it returns OEMCrypto_ERROR_NO_CONTENT_KEY. The developer of the * OEMCrypto library must be careful that the keys themselves are not * accidentally revealed. @@ -2091,15 +1692,265 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, /// @} +/// @addtogroup entitled +/// @{ + +/** + * This method creates an entitled key session. + * OEMCrypto is required to support at least one entitled key session per + * license. For CAS support, we also require that OEMCrypto support at least + * six entitled key sessions per license. + * + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the created entitled key session. + * @param[out] key_session: id of the created entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_TOO_MANY_SESSIONS + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this oec_session. It will not be called simultaneously with + * initialization or usage table functions. It is as if the CDM holds a write + * lock for this session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_CreateEntitledKeySession( + OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session); + +/** + * This method which removes an entitled key session. + * + * @param[in] key_session: id of the entitled key session to be removed. + * + * Returns: + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( + OEMCrypto_SESSION key_session); + +/** + * Load content keys into an entitled session which is associated with an + * entitlement sessions. This function will only be called for an entitled + * session after a call to OEMCrypto_LoadLicense() has been called on the + * associated entitlement session. This function may be called multiple times + * for the same session. + * + * If the session is not an entitled session, return + * OEMCrypto_ERROR_INVALID_CONTEXT and perform no work. + * + * For each key object in key_array, OEMCrypto shall look up the entry in the + * key table for the entitlement session with the corresponding + * entitlement_key_id. + * + * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2. If the entry already has a content_key_id and content_key_data, that + * id and data are erased. + * 3. The content_key_id from the key_array is copied to the entry's + * content_key_id. + * 4. The content_key_data decrypted using the entitlement_key_data as a + * key for AES-256-CBC with an IV of content_key_data_iv. Notice that + * the entitlement key will be an AES 256 bit key. The clear content key + * data will be stored in the entry's content_key_data. + * Entries in the key table that do not correspond to anything in the + * key_array are not modified or removed. + * + * For devices that use a hardware key ladder, it may be more convenient to + * store the encrypted content key data in the key table, and decrypt it when + * the function SelectKey is called. + * + * @param[in] session: handle for the entitled key session to be used. + * @param[in] message: pointer to memory containing message to be verified. + * @param[in] message_length: length of the message, in bytes. + * @param[in] key_array_length: number of keys present. + * @param[in] key_array: set of key updates. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_KEY_NOT_ENTITLED + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * + * @buffer_size + * OEMCrypto shall support message sizes as described in the section + * OEMCrypto_ResourceRatingTier(). + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session, or its entitlement session. It will not be called + * simultaneously with initialization or usage table functions. It is as if + * the CDM holds a write lock for this session, and a read lock on the + * OEMCrypto system. + * + * @version + * This method changed in API version 17. + */ +OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); + +/** + * This method associates an existing entitled key session to the specified + * OEMCrypto session. + * + * @param[in] key_session: id of the entitled key session. + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_INVALID_SESSION + * + * @threading + * This is a "Session Initialization Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock + * on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); + +/** + * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an + * entitled key session, which already has entitlement keys loaded. Used only by + * CAS. + * + * This function will only be called for a session after a call to + * OEMCrypto_LoadLicense with the license_type equal to + * OEMCrypto_EntitlementLicense, and a call to + * OEMCrypto_CreateEntitledKeySession initializing the entitled key session. + * This function may be called multiple times for the same session. + * + * For each key object, odd and even, OEMCrypto shall look up the entry in the + * key table with the corresponding entitlement_key_id. Before the + * entitlement_key is used: + * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2) Check the entitlement key’s key control block use. If failed, return + * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT, + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 3) If the entitlement key’s control block has a nonzero Duration field, + * then the API shall verify that the duration is greater than the + * session’s elapsed time clock before the key is used. OEMCrypto will + * return OEMCrypto_ERROR_KEY_EXPIRED. + * 4) The content_key_data decrypted using the entitlement_key_data as a key + * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is + * padded using PKCS#7 padding. Notice that the entitlement key will be an + * AES 256 bit key. The clear content key data will be stored in the + * entry’s content_key_data. + * 5) The decrypted content key data may be set in a hardware KeySlot, + * together with content iv and cipher mode information, which can be used + * by the Descrambler in TunerHal. The entitled key session ID may be used + * as the key token to uniquely identify the content key in KeySlot. + * + * @param[in] session: handle for the entitled key session to be used. + * @param[in] message: pointer to memory containing message to be verified. + * @param[in] message_length: length of the message, in bytes. + * @param[in] even_key: key update for the even ecm key. May be null if the key + * does not change. + * @param[in] odd_key: key update for the odd ecm key. May be null if the key + * does not change. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_KEY_NOT_ENTITLED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_KEY_EXPIRED + * @retval OEMCrypto_ERROR_ANALOG_OUTPUT + * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); + +/** + * Retrieves the key token associated with the input entitled key session. This + * method is currently used only by CAS, where key token is a means to share + * vendor specific crypto info with other frameworks (e.g. Descrambler in + * Android TunerHAL) that are also under control of the vendor. + * + * @param[in] key_session: handle for the entitled key session to be used. + * @param[out] key_token: where the key token is stored. + * @param[in,out] key_token_length: length of the key token, in bytes. + * + * @retval OEMCrypto_SUCCESS on success + * @retval OEMCrypto_ERROR_SHORT_BUFFER if buffer_length is too small. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * + * @threading + * This is an "Initialization and Termination Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock on + * the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session, + uint8_t* key_token, + size_t* key_token_length); + +/// @} + /// @addtogroup decryption /// @{ /** * Select a content key and install it in the hardware key ladder for - * subsequent decryption operations (OEMCrypto_DecryptCENC()) for this - * session. The specified key must have been previously "installed" via - * OEMCrypto_LoadKeys(), OEMCrypto_LoadLicense(), or - * OEMCrypto_LoadEntitledContentKeys(). + * subsequent decryption operations. (e.g. OEMCrypto_DecryptCENC(), generic + * crypto functions) The specified key must have been previously imported via + * OEMCrypto_LoadLicense() or OEMCrypto_LoadEntitledContentKeys(). Write a + * handle that can be used to refer to the installed key into the buffer pointed + * to by the key_handle parameter and set key_handle_length to the size of the + * data written to key_handle. + * + * If key_handle is NULL or key_handle_length is too small to hold the handle, + * write the number of bytes needed to hold a key handle to key_handle_length + * and return OEMCrypto_ERROR_SHORT_BUFFER. Do not install the key in this case. + * + * If the session has an entry in the Usage Table and the status of the entry is + * "unused", then change the status to "active" and set the + * time_of_first_decrypt. * * A key control block is associated with the key and the session, and is * used to configure the session context. The Key Control data is documented @@ -2116,9 +1967,44 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * 256 bits it will be used for OEMCrypto_Generic_Sign() or * OEMCrypto_Generic_Verify() as specified in the key control block. If the key * will be used for OEMCrypto_Generic_Encrypt() or OEMCrypto_Generic_Decrypt() - * then the cipher mode will always be OEMCrypto_CipherMode_CBCS. Continue to - * use this key for this session until OEMCrypto_SelectKey() is called again, - * or until OEMCrypto_CloseSession() is called. + * then the cipher mode will always be OEMCrypto_CipherMode_CBCS. + * + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt should latch the key into + * secure crypto hardware such that it can be fed by the chosen bypass method. + * For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * If the device is bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. The hardware that the key is latched into must be able + * to enforce that the key expires and becomes unusable after the amount of + * time returned by ODK in the timer_value field. + * + * The format of the key handle is opaque to Widevine and platform-specific. It + * should contain whatever information the platform will need to find the key in + * the hardware on the bypass decryption path, as well as in + * OEMCrypto_DecryptCENC() and the generic crypto functions. A key slot number + * is generally not sufficient, as this could lead to the wrong key being used + * if that slot later has a different key loaded into it. + * + * The key handle must not contain the actual cryptographic key. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. These devices may latch the + * key to the session and continue to use this key for this session until + * OEMCrypto_SelectKey() is called again, or until OEMCrypto_CloseSession() is + * called. + * + * The "key handle" in this mode is the session ID. Platforms should request a + * 4-byte key handle buffer and copy the session ID into it. * * @verification * 1. If the key id is not found in the keytable for this session, then the @@ -2146,8 +2032,15 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * @param[in] cipher_mode: whether the key should be prepared for CTR mode or * CBC mode when used in later calls to DecryptCENC. This should be ignored * when the key is used for Generic Crypto calls. + * @param[out] key_handle: pointer to a buffer in which the key handle should be + * stored. May be NULL on the first call in order to find required buffer + * size. + * @param[in,out] key_handle_length: (in) length of the key_handle buffer, in + * bytes. (out) actual length of the key handle written to the key_handle + * buffer, in bytes. May not be NULL. * * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_SHORT_BUFFER if the buffer is NULL or too small * @retval OEMCrypto_ERROR_KEY_EXPIRED if the session's timer has expired * @retval OEMCrypto_ERROR_INVALID_SESSION crypto session ID invalid or not open * @retval OEMCrypto_ERROR_NO_DEVICE_KEY failed to decrypt device key @@ -2170,16 +2063,18 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. + * This method is new in API version 18. */ -OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, - const uint8_t* content_key_id, - size_t content_key_id_length, - OEMCryptoCipherMode cipher_mode); +OEMCryptoResult OEMCrypto_GetKeyHandle(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, + uint8_t* key_handle, + size_t* key_handle_length); /** * Decrypts or copies a series of input payloads into output buffers using - * the session context indicated by the session parameter. The input payload + * the installed key indicated by the key handle parameter. The input payload * is delivered in the form of samples. The samples are subdivided into * subsamples. "Samples" and "subsamples" are defined as in the ISO Common * Encryption standard (ISO/IEC 23001-7:2016). The samples parameter contains @@ -2196,7 +2091,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * * Decryption mode is AES-128-CTR or AES-128-CBC depending on the value of * cipher_mode previously passed in to OEMCrypto_SelectKey(). For the encrypted - * portion of subsamples, the content key associated with the session is + * portion of subsamples, the content key associated with the handle is * latched in the active hardware key ladder and is used for the decryption * operation. For the clear portion of subsamples, the data is simply copied. * @@ -2212,6 +2107,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * buffer. * 3. The structure OEMCrypto_DestBufferDesc indicates that the data should * be sent directly to the decoder and renderer. + * * Depending on your platform's needs, you may not need to support all three * of these options. * @@ -2408,10 +2304,6 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * OEMCrypto_DecryptCENC() begins storing data buffers.output.secure.offset * bytes after the beginning of the secure buffer. * - * If the session has an entry in the Usage Table, then OEMCrypto must update - * the time_of_last_decrypt. If the status of the entry is "unused", then - * change the status to "active" and set the time_of_first_decrypt. - * * OEMCrypto cannot assume that the buffers of consecutive samples are * consecutive in memory. * @@ -2436,14 +2328,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * OEMCrypto_ERROR_UNKNOWN_FAILURE if the subsamples are larger than the * input buffer. No decryption should be performed in this case. * If the subsamples all contain only clear bytes, then no further - * verification is performed. This call shall copy clear data even when there - * are no keys loaded, or there is no selected key. - * If this is the first use of a key for this session, then OEMCrypto shall - * call ODK_AttemptFirstPlayback to update the session's clock values and - * verify playback is allowed. If this is not the first use of a key for this - * session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See - * [ODK Clocks and Timers](../../odk-timers) for handling the return value of - * these ODK functions. + * verification is performed. * The following checks should be performed if any subsamples contain any * encrypted bytes. If any check fails, an error is returned, and no * decryption is performed. @@ -2470,9 +2355,9 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * restrict those displays, return * OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION. (See note on delayed * error conditions below) - * 5. If the current session has an entry in the Usage Table, and the - * status of that entry is either kInactiveUsed or kInactiveUnused, then - * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 5. If the current key has an entry in the Usage Table, and the status of + * that entry is either kInactiveUsed or kInactiveUnused, then return the + * error OEMCrypto_ERROR_LICENSE_INACTIVE. * 6. If a Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash(), * and the current key's control block does not have the * Allow_Hash_Verification bit set, then do not compute a hash and @@ -2505,8 +2390,33 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * In either case, a call to OEMCrypto_GetHDCPCapability() shall return the * current HDCP level. * - * @param[in] session: Crypto or entitled session identifier. The crypto session - * in which decrypt is to be performed. + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt are still required to implement + * this function so that the decrypt path can be tested. It is acceptable for + * this function to invoke the bypass mechanism instead of calling into the + * OEMCrypto TA. For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. The "key handle" created by + * OEMCrypto_GetKeyHandle() is the session ID, as described above, and can be + * used the same as the session ID previously passed to OEMCrypto_DecryptCENC(). + * + * If the device is not bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. + * + * @param[in] key_handle: pointer to a buffer containing the key handle for a + * key previously installed with OEMCrypto_GetKeyHandle(). + * @param[in] key_handle_length: length of the data in the key_handle buffer, in + * bytes. * @param[in] samples: A caller-owned array of OEMCrypto_SampleDescription * structures. Each entry in this array contains one sample of the content. * @param[in] samples_length: The length of the array pointed to by the samples @@ -2552,16 +2462,21 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * @threading * This is a "Session Function" and may be called simultaneously with session * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. + * for the session containing the key. It will not be called simultaneously + * with initialization or usage table functions. It is as if the CDM holds a + * write lock for the key's session, and a read lock on the OEMCrypto system. + * + * The threading guarantees for this function are only guaranteed when the + * function is called through the Widevine CDM. If the platform uses Bypass + * Decrypt in a way that still calls this function, the OS may call this + * function in ways that violate these threading guarantees. * * @version - * This method changed in API version 17. This method changed its name in API + * This method changed in API version 18. This method changed its name in API * version 11. */ OEMCryptoResult OEMCrypto_DecryptCENC( - OEMCrypto_SESSION session, + const uint8_t* key_handle, size_t key_handle_length, const OEMCrypto_SampleDescription* samples, // an array of samples. size_t samples_length, // the number of samples. const OEMCrypto_CENCEncryptPatternDesc* pattern); @@ -2651,31 +2566,44 @@ OEMCryptoResult OEMCrypto_CopyBuffer( uint8_t subsample_flags); /** - * This function encrypts a generic buffer of data using the current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * the time_of_last_decrypt. If the status of the entry is "unused", then - * change the status to "active" and set the time_of_first_decrypt. + * This function encrypts a generic buffer of data using the given key. * * OEMCrypto shall be able to handle buffers at least 100 KiB long. * + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt are still required to implement + * this function. For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. The "key handle" created by + * OEMCrypto_GetKeyHandle() is the session ID, as described above, and can be + * used the same as the session ID previously passed to OEMCrypto_DecryptCENC(). + * + * If the device is not bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. + * * @verification * The following checks should be performed. If any check fails, an error is * returned, and the data is not encrypted. - * 1. The control bit for the current key shall have the Allow_Encrypt set. - * If not, return OEMCrypto_ERROR_UNKNOWN_FAILURE. - * 2. If this is the first use of a key for this session, then OEMCrypto - * shall call ODK_AttemptFirstPlayback to update the session's clock - * values and verify playback is allowed. If this is not the first use - * of a key for this session, then OEMCrypto shall call - * ODK_UpdateLastPlaybackTime. - * See [ODK Clocks and Timers](../../odk-timers) for handling the return - * value of these ODK functions. - * 3. If the current session has an entry in the Usage Table, and the - * status of that entry is either kInactiveUsed or kInactiveUnused, then - * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 1. The control bit for the key shall have the Allow_Encrypt set. If not, + * return OEMCrypto_ERROR_UNKNOWN_FAILURE. + * 2. If the key has an entry in the Usage Table, and the status of that + * entry is either kInactiveUsed or kInactiveUnused, then return the + * error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto or entitled key session identifier. + * @param[in] key_handle: pointer to a buffer containing the key handle for a + * key previously installed with OEMCrypto_GetKeyHandle(). + * @param[in] key_handle_length: length of the data in the key_handle buffer, in + * bytes. * @param[in] in_buffer: pointer to memory containing data to be encrypted. * @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm * may restrict in_buffer_length to be a multiple of block size. @@ -2698,7 +2626,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer( * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size - * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * OEMCrypto shall support buffer sizes of at least 100 KiB for generic * crypto operations. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is * larger than the supported size. @@ -2706,46 +2634,60 @@ OEMCryptoResult OEMCrypto_CopyBuffer( * @threading * This is a "Session Function" and may be called simultaneously with session * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. + * for the session containing the key. It will not be called simultaneously + * with initialization or usage table functions. It is as if the CDM holds a + * write lock for the key's session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 17. + * This method changed in API version 18. */ OEMCryptoResult OEMCrypto_Generic_Encrypt( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, OEMCrypto_SharedMemory* out_buffer); /** - * This function decrypts a generic buffer of data using the current key. - * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * the time_of_last_decrypt. If the status of the entry is "unused", then - * change the status to "active" and set the time_of_first_decrypt. + * This function decrypts a generic buffer of data using the given key. * * OEMCrypto should be able to handle buffers at least 100 KiB long. * + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt are still required to implement + * this function. For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. The "key handle" created by + * OEMCrypto_GetKeyHandle() is the session ID, as described above, and can be + * used the same as the session ID previously passed to OEMCrypto_DecryptCENC(). + * + * If the device is not bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. + * * @verification * The following checks should be performed. If any check fails, an error is * returned, and the data is not decrypted. - * 1. The control bit for the current key shall have the Allow_Decrypt set. - * If not, return OEMCrypto_ERROR_DECRYPT_FAILED. - * 2. If the current key's control block has the Data_Path_Type bit set, - * then return OEMCrypto_ERROR_DECRYPT_FAILED. - * 3. If this is the first use of a key for this session, then OEMCrypto - * shall call ODK_AttemptFirstPlayback to update the session's clock - * values and verify playback is allowed. If this is not the first use - * of a key for this session, then OEMCrypto shall call - * ODK_UpdateLastPlaybackTime. - * See [ODK Clocks and Timers](../../odk-timers) for handling the return - * value of these ODK functions. - * 4. If the current session has an entry in the Usage Table, and the - * status of that entry is either kInactiveUsed or kInactiveUnused, then - * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 1. The control bit for the key shall have the Allow_Decrypt set. If not, + * return OEMCrypto_ERROR_DECRYPT_FAILED. + * 2. If the key's control block has the Data_Path_Type bit set, then return + * OEMCrypto_ERROR_DECRYPT_FAILED. + * 3. If the key has an entry in the Usage Table, and the status of that + * entry is either kInactiveUsed or kInactiveUnused, then return the + * error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto or entitled key session identifier. + * @param[in] key_handle: pointer to a buffer containing the key handle for a + * key previously installed with OEMCrypto_GetKeyHandle(). + * @param[in] key_handle_length: length of the data in the key_handle buffer, in + * bytes. * @param[in] in_buffer: pointer to memory containing data to be encrypted. * @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm * may restrict in_buffer_length to be a multiple of block size. @@ -2769,7 +2711,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size - * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * OEMCrypto shall support buffer sizes of at least 100 KiB for generic * crypto operations. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is * larger than the supported size. @@ -2777,41 +2719,55 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( * @threading * This is a "Session Function" and may be called simultaneously with session * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. + * for the session containing the key. It will not be called simultaneously + * with initialization or usage table functions. It is as if the CDM holds a + * write lock for the key's session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 17. + * This method changed in API version 18. */ OEMCryptoResult OEMCrypto_Generic_Decrypt( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, OEMCrypto_SharedMemory* out_buffer); /** - * This function signs a generic buffer of data using the current key. + * This function signs a generic buffer of data using the given key. * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * the time_of_last_decrypt. If the status of the entry is "unused", then - * change the status to "active" and set the time_of_first_decrypt. + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt are still required to implement + * this function. For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. The "key handle" created by + * OEMCrypto_GetKeyHandle() is the session ID, as described above, and can be + * used the same as the session ID previously passed to OEMCrypto_DecryptCENC(). + * + * If the device is not bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. * * @verification * The following checks should be performed. If any check fails, an error is * returned, and the data is not signed. - * 1. The control bit for the current key shall have the Allow_Sign set. - * 2. If this is the first use of a key for this session, then OEMCrypto - * shall call ODK_AttemptFirstPlayback to update the session's clock - * values and verify playback is allowed. If this is not the first use - * of a key for this session, then OEMCrypto shall call - * ODK_UpdateLastPlaybackTime. - * See [ODK Clocks and Timers](../../odk-timers) for handling the return - * value of these ODK functions. - * 3. If the current session has an entry in the Usage Table, and the - * status of that entry is either kInactiveUsed or kInactiveUnused, then - * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 1. The control bit for the key shall have the Allow_Sign set. + * 2. If the key has an entry in the Usage Table, and the status of that + * entry is either kInactiveUsed or kInactiveUnused, then return the + * error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto or entitled key session identifier. + * @param[in] key_handle: pointer to a buffer containing the key handle for a + * key previously installed with OEMCrypto_GetKeyHandle(). + * @param[in] key_handle_length: length of the data in the key_handle buffer, in + * bytes. * @param[in] buffer: pointer to memory containing data to be encrypted. * @param[in] buffer_length: length of the buffer, in bytes. * @param[in] algorithm: Specifies which algorithm to use. @@ -2836,7 +2792,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size - * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * OEMCrypto shall support buffer sizes of at least 100 KiB for generic * crypto operations. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is * larger than the supported size. @@ -2844,14 +2800,15 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( * @threading * This is a "Session Function" and may be called simultaneously with session * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. + * for the session containing the key. It will not be called simultaneously + * with initialization or usage table functions. It is as if the CDM holds a + * write lock for the key's session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 17. + * This method changed in API version 18. */ -OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, +OEMCryptoResult OEMCrypto_Generic_Sign(const uint8_t* key_handle, + size_t key_handle_length, const OEMCrypto_SharedMemory* buffer, size_t buffer_length, OEMCrypto_Algorithm algorithm, @@ -2860,34 +2817,47 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, /** * This function verifies the signature of a generic buffer of data using the - * current key. + * given key. * - * If the session has an entry in the Usage Table, then OEMCrypto will update - * the time_of_last_decrypt. If the status of the entry is "unused", then - * change the status to "active" and set the time_of_first_decrypt. + * #### Bypass Decrypt + * + * Platforms that wish to support Bypass Decrypt are still required to implement + * this function. For more information on Bypass Decrypt, see the + * [Bypass Decrypt](../../bypass) documentation. + * + * #### Non-Bypass Decrypt + * + * For platforms that do not need to support Bypass Decrypt, a mode compatible + * with previous versions of OEMCrypto is available. The "key handle" created by + * OEMCrypto_GetKeyHandle() is the session ID, as described above, and can be + * used the same as the session ID previously passed to OEMCrypto_DecryptCENC(). + * + * If the device is not bypassing, it must update the ODK clock values in this + * function call. If this is the first use of a key for this session, then + * OEMCrypto shall call ODK_AttemptFirstPlayback to update the session's clock + * values and verify playback is allowed. If this is not the first use of a key + * for this session, then OEMCrypto shall call ODK_UpdateLastPlaybackTime. See + * [ODK Clocks and Timers](../../odk-timers) for handling the return value of + * these ODK functions. * * @verification * The following checks should be performed. If any check fails, an error is * returned. - * 1. The control bit for the current key shall have the Allow_Verify set. + * 1. The control bit for the key shall have the Allow_Verify set. * 2. The signature of the message shall be computed, and the API shall * verify the computed signature matches the signature passed in. If * not, return OEMCrypto_ERROR_SIGNATURE_FAILURE. * 3. The signature verification shall use a constant-time algorithm (a * signature mismatch will always take the same time as a successful * comparison). - * 4. If this is the first use of a key for this session, then OEMCrypto - * shall call ODK_AttemptFirstPlayback to update the session's clock - * values and verify playback is allowed. If this is not the first use - * of a key for this session, then OEMCrypto shall call - * ODK_UpdateLastPlaybackTime. - * See [ODK Clocks and Timers](../../odk-timers) for handling the return - * value of these ODK functions. - * 5. If the current session has an entry in the Usage Table, and the - * status of that entry is either kInactiveUsed or kInactiveUnused, then - * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. + * 4. If the key has an entry in the Usage Table, and the status of that + * entry is either kInactiveUsed or kInactiveUnused, then return the + * error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto or entitled key session identifier. + * @param[in] key_handle: pointer to a buffer containing the key handle for a + * key previously installed with OEMCrypto_GetKeyHandle(). + * @param[in] key_handle_length: length of the data in the key_handle buffer, in + * bytes. * @param[in] buffer: pointer to memory containing data to be encrypted. * @param[in] buffer_length: length of the buffer, in bytes. * @param[in] algorithm: Specifies which algorithm to use. @@ -2908,7 +2878,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size - * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * OEMCrypto shall support buffer sizes of at least 100 KiB for generic * crypto operations. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is * larger than the supported size. @@ -2916,17 +2886,18 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, * @threading * This is a "Session Function" and may be called simultaneously with session * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. + * for the session containing the key. It will not be called simultaneously + * with initialization or usage table functions. It is as if the CDM holds a + * write lock for the key's session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 17. + * This method changed in API version 18. */ OEMCryptoResult OEMCrypto_Generic_Verify( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, size_t signature_length); + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + size_t signature_length); /// @} @@ -3158,6 +3129,10 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data, size_t* key_data_length); +/// @} + +/// @addtogroup test_verify +/// @{ /** * Temporarily use the specified test keybox until the next call to * OEMCrypto_Terminate(). This allows a standard suite of unit tests to be run @@ -3264,38 +3239,6 @@ typedef enum OEMCrypto_Security_Level { OEMCrypto_Level3 = 3, } OEMCrypto_Security_Level; -/** - * Returns a buffer filled with hardware-generated random bytes, if supported - * by the hardware. If the hardware feature does not exist, return - * OEMCrypto_ERROR_RNG_NOT_SUPPORTED. - * - * @param[out] random_data: pointer to the buffer that receives random data - * @param[in] random_data_length: length of the random data buffer in bytes - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_RNG_FAILED failed to generate random number - * @retval OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * - * @buffer_size - * OEMCrypto shall support random_data_length sizes of at least 32 bytes - * for random number generation. - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * @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 supported in all API versions. - */ -OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, - size_t random_data_length); - /** * This function returns the current API version number. The version number * allows the calling application to avoid version mis-match errors, because @@ -3350,31 +3293,48 @@ uint32_t OEMCrypto_MinorAPIVersion(void); /** * Stores the build information of the OEMCrypto library in a buffer. This - * string should be updated with each release or OEMCrypto build. If - * buffer_length is not enough, the function will return + * string should be updated with each release or OEMCrypto build. + * + * It may be used for logging or bug tracking and may be bubbled up to the + * app so that it may track metrics on errors. + * + * The returned string must be JSON formatted. It shall also contain the + * following top level values [data types in brackets]: + * - "soc_vendor" [string]: SOC manufacturer name + * - "soc_model" [string]: SOC model name + * - "ta_ver" [string]: TA version in string format eg "1.12.3+tag", "2.0" + * - "uses_opk" [bool]: Whether TA was built with Widevine's OPK + * - "tee_os" [string]: Trusted OS intended to run the TA, eg "Trusty", "QSEE", + * "OP-TEE" + * - "tee_os_ver" [string]: Version of Trusted OS intended to run the TA + * - "is_debug" [bool]: Whether this is a debug build of the TA. Debug builds + * can enter Test Mode via OEMCrypto_EnterTestMode(), while production builds + * cannot. Debug builds are not released to the public. + * + * While not required, the following top level fields are recommended: + * - "implementer" [string]: Name of company or entity that provides OEMCrypto. + * Important if not SOC vendor. + * + * The JSON string can contain other values, structs, arrays, etc in addition to + * the above, if desired. + * + * If buffer_length is not enough, the function will return * OEMCrypto_ERROR_SHORT_BUFFER. Before returning OEMCrypto_ERROR_SHORT_BUFFER, * the function should set buffer_length to the length of buffer needed. If the * write is successful, buffer_length will be set to the number of bytes * written. * - * Some SOC vendors deliver a binary OEMCrypto library to a device - * manufacturer. This means the OEMCrypto version may not be exactly in sync - * with the system's versions. This string can be used to help track which - * version is installed on a device. - * - * It may be used for logging or bug tracking and may be bubbled up to the - * app so that it may track metrics on errors. - * - * Since the OEMCrypto API also changes its minor version number when there - * are minor corrections, it would be useful to include the API version - * number in this string, e.g. "15.1" or "15.2" if those minor versions are - * released. + * The returned data shall be no larger than 1024 bytes. If the buffer length is + * larger, this function will return OEMCrypto_ERROR_BUFFER_TOO_LARGE and set + * |buffer_length| to 1024. * * @param[out] buffer: pointer to the buffer that receives build information * @param[in,out] buffer_length: length of the data buffer in bytes * * @retval OEMCrypto_SUCCESS * @retval OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small. + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is too large. + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failure. * * @threading * This is a "Property Function" and may be called simultaneously with any @@ -3767,7 +3727,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void); * The message size limit applies to all functions that sign or verify a * message: OEMCrypto_PrepAndSignLicenseRequest(), * OEMCrypto_PrepAndSignRenewalRequest(), - * OEMCrypto_PrepAndSignProvisioningRequest(), and OEMCrypto_LoadKeys(). A + * OEMCrypto_PrepAndSignProvisioningRequest(), and OEMCrypto_LoadLicense(). A * request message is also used as the context buffer in * OEMCrypto_DeriveKeysFromSessionKey() and OEMCrypto_GenerateDerivedKeys(). * @@ -3857,6 +3817,44 @@ OEMCryptoResult OEMCrypto_ProductionReady(void); */ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); +/** + * Queries the hash algorithm that the device will use when performing + * RSASSA-PSS or ECDSA with the private key currently loaded in the given + * session. + * + * For RSA keys, SHA-1 was used for all OEMCrypto versions prior to 18, but + * SHA-256 is strongly recommended for all devices. SHA-384 and SHA-512 are not + * supported with RSA keys. + * + * For ECC keys, the algorithm chosen depends on the curve used to generate the + * key, as outlined in the OEMCrypto Integration Guide. SHA-1 is not supported + * with ECC keys. + * + * For devices that do not support ECC, it is acceptable for this function to + * return a hardcoded value, since the answer does not depend on the currently + * loaded private key. + * + * @param[in] session: crypto session identifier. + * @param[out] algorithm: the algorithm the device will use. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 18. + */ +OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm( + OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm); + /// @} /// @addtogroup drm_cert @@ -3868,11 +3866,14 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); * key and signing key generated using an algorithm at least as strong as * that in GenerateDerivedKeys. * - * First, OEMCrypto shall verify the signature of the message using - * HMAC-SHA256 with the derived mac_key[server]. The signature verification - * shall use a constant-time algorithm (a signature mismatch will always take - * the same time as a successful comparison). The signature is over the - * entire message buffer starting at message with length message_length. If + * First, OEMCrypto shall verify the signature of the message using the correct + * algorithm depending on if the device supports Provisioning 2.0, 3.0 or 4.0. + * + * For Provisioning 2.0, OEMCrypto shall verify the signature of the message + * using HMAC-SHA256 with the derived mac_key[server]. The signature + * verification shall use a constant-time algorithm (a signature mismatch will + * always take the same time as a successful comparison). The signature is over + * the entire message buffer starting at message with length message_length. If * the signature verification fails, ignore all other arguments and return * OEMCrypto_ERROR_SIGNATURE_FAILURE. * @@ -3880,7 +3881,10 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); * and encrypt_key with a call to OEMCrypto_DeriveKeysFromSessionKey() or * OEMCrypto_GenerateDerivedKeys(). * - * The function ODK_ParseProvisioning is called to parse the message. If it + * For Provisioning 3.0 and 4.0, the signature is not verified. + * + * After the signature is verified, + * the function ODK_ParseProvisioning is called to parse the message. If it * returns an error, OEMCrypto shall return that error to the CDM layer. The * function ODK_ParseProvisioning is described in the document "Widevine Core * Message Serialization". @@ -4063,8 +4067,8 @@ OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(OEMCrypto_SESSION session, * on a production device without permanently changing the key. Using the * test key is not persistent. * - * The test key can be found in the unit test code, oemcrypto_test.cpp, in - * PKCS8 form as the constant kTestRSAPKCS8PrivateKeyInfo2_2048. + * The test key can be found in the OEMCrypto unit test, in PKCS8 form as the + * constant kTestRSAPKCS8PrivateKeyInfo2_2048. * * @retval OEMCrypto_SUCCESS success * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES @@ -4157,22 +4161,31 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( RSA_Padding_Scheme padding_scheme); /** - * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described - * in the document "Widevine Core Message Serialization", to prepare the core - * message. If it returns an error, the error should be returned by OEMCrypto - * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall - * compute the signature of the entire message. The entire message is the - * buffer starting at message with length message_length. + * OEMCrypto will use ODK_PrepareCoreProvisioningRequest() or + * ODK_PrepareCoreProvisioning40Request(), as described in the document + * "Widevine Core Message Serialization", to prepare the core message. + * ODK_PrepareCoreProvisioningRequest() for Provisioning 2 or 3, and + * ODK_PrepareCoreProvisioning40Request() for Provisioning 4. If the ODK + * function returns an error, the error should be returned by OEMCrypto to the + * CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall compute the + * signature of the entire message. The entire message is the buffer starting at + * message with length message_length. * * For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign * the request with the session's derived client mac key from the previous * call to OEMCrypto_GenerateDerivedKeys(). * - * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto - * will sign the request with the private key associated with the OEM + * For Provisioning 3.0, i.e. a device that has a baked in OEM Certificate, + * OEMCrypto will sign the request with the private key associated with the OEM * Certificate. The key shall have been loaded by a previous call to * OEMCrypto_LoadDRMPrivateKey(). * + * For Provisioning 4.0, i.e. a device that uses a Boot Chain Certificate to + * request and OEM cert, a request for an OEM cert is signed by the OEM private + * key. A request for a DRM cert is signed by the DRM private key. The DRM cert + * that was generated on the device in OEMCrypto_GenerateCertificateKeyPair() is + * signed by the OEM cert private key. + * * Refer to the Signing Messages Sent to a Server section above for more * details. * @@ -4850,11 +4863,160 @@ OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, OEMCrypto_PrivateKeyType* key_type); +/** + * Get the serialized device information in CBOR map format. + * + * The device + * information may contain, for example, device make and model, "fused" status, + * and other properties, which is intended to be 1) uploaded during device + * manufacture in the factory, 2) checked by the server to verify that the + * provisioning request is coming from the expected device in the fields, based + * on the values previously uploaded and registered. + * + * This method is used by provisioning 4 only. + * + * @param[out] device_info: pointer to the buffer that receives the serialized + * device information in CBOR map format. + * @param[in,out] device_info_length: on input, size of the caller's + * device_info buffer. On output, the number of bytes written into the buffer. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER if device_info_length is too small to + * return the device_info. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4 is not supported, + * or device information is not available on the platform. + * + * @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 in API version 18. + */ +OEMCryptoResult OEMCrypto_GetDeviceInformation(uint8_t* device_info, + size_t* device_info_length); + +/** + * Get the serialized signed Certificate Signing Request (Csr) payload in + * COSE_Sign1 format. + * + * The signed CSR payload contains challenge and device information. It is + * signed by the leaf cert of the boot certificate chain (BCC). It is only used + * in the factory, uploaded and validated during device registration. + * + * This method is used by provisioning 4 only. + * + * @param[in] challenge: pointer to the buffer containing a byte string to be + * signed. + * @param[in] challenge_length: size of the challenge buffer. + * @param[in] encoded_device_info: pointer to the buffer containing the + * serialized device information in CBOR map format. + * @param[in] encoded_device_info_length: size of the encoded_device_info + * buffer. + * @param[out] signed_csr_payload: pointer to the buffer that receives the + * serialized CSR payload in COSE_Sign1 format. + * @param[in,out] signed_csr_payload_length: on input, size of the caller's + * signed_csr_payload buffer. On output, the number of bytes written into the + * buffer. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if challenge_length or + * encoded_device_info_length is 0, or any pointer is NULL + * @retval OEMCrypto_ERROR_SHORT_BUFFER if signed_csr_payload_length is too + * small to return the signed_csr_payload. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4 is not supported, + * or device information is not available on the platform. + * + * @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 in API version 18. + */ +OEMCryptoResult OEMCrypto_GetDeviceSignedCsrPayload( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + uint8_t* signed_csr_payload, size_t* signed_csr_payload_length); + +/** + * Loads an OEM private key to a session. The key will be used in signing DRM + * certificate request, or the public key generated by calling + * OEMCrypto_GenerateCertificateKeyPair. + * + * @param[in] session: session id. + * @param[in] key_type: type of the leaf key (RSA or ECC). + * @param[in] wrapped_private_key: the encrypted private key. This is the + * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair. + * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in + * bytes. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_NO_DEVICE_KEY + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_KEY + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_InstallOemPrivateKey( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); /// @} /// @addtogroup test_verify /// @{ +/** + * Enter Test Mode. This enables OEMCrypto test functionality. Without a call to + * this function, none of the test functions](./test-verify) shall be + * enabled. After this function has been called, OEMCrypto will not use the + * production keybox. Once OEMCrypto has entered Test Mode, it will not leave + * Test Mode until the next reboot. + * + * If the device is not in Test Mode, it will be in Production Mode and + * OEMCrypto will use a production root of trust (keybox or OEM Certificate) if + * available. In Production Mode, none of the test functions are enabled. + * + * Widevine recommends shipping a Production Only version of OEMCrypto on + * released devices. A Production Only version of OEMCrypto will have all test + * functions disabled. In this case, OEMCrypto_EnterTestMode() will return + * OEMCRYPTO_ERROR_NOT_IMPLEMENTED. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED OEMCrypto is a production build, and + * does not support debug or test-only functions. + * + * @threading + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. It is called once after + * OEMCrypto_Initialize(), and before any other test-only functions are + * called. + * + * @version + * This method is new in API version 18. + */ +OEMCryptoResult OEMCrypto_EnterTestMode(void); + /** * Returns the type of hash function supported for Full Decrypt Path Testing. * A hash type of OEMCrypto_Hash_Not_Supported = 0 means this feature is not @@ -5060,140 +5222,15 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer( OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor, int secure_fd); -/** - * Loads an OEM private key to a session. The key will be used in signing DRM - * certificate request, or the public key generated by calling - * OEMCrypto_GenerateCertificateKeyPair. - * - * @param[in] session: session id. - * @param[in] key_type: type of the leaf key (RSA or ECC). - * @param[in] wrapped_private_key: the encrypted private key. This is the - * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair. - * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in - * bytes. - * - * @retval OEMCrypto_SUCCESS - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_NO_DEVICE_KEY - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_KEY - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_InstallOemPrivateKey( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); - /// @} -/** - * This method associates an existing entitled key session to the specified - * OEMCrypto session. - * - * @param[in] key_session: id of the entitled key session. - * @param[in] oec_session: handle for the OEMCrypto session to be associated - * with the entitled key session. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * @retval OEMCrypto_ERROR_INVALID_SESSION - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); - -/** - * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an - * entitled key session, which already has entitlement keys loaded. Used only by - * CAS. - * - * This function will only be called for a session after a call to - * OEMCrypto_LoadKeys with the license_type equal to - * OEMCrypto_EntitlementLicense, and a call to - * OEMCrypto_CreateEntitledKeySession initializing the entitled key session. - * This function may be called multiple times for the same session. - * - * For each key object, odd and even, OEMCrypto shall look up the entry in the - * key table with the corresponding entitlement_key_id. Before the - * entitlement_key is used: - * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. - * 2) Check the entitlement key’s key control block use. If failed, return - * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT, - * OEMCrypto_ERROR_INSUFFICIENT_HDCP. - * 3) If the entitlement key’s control block has a nonzero Duration field, - * then the API shall verify that the duration is greater than the - * session’s elapsed time clock before the key is used. OEMCrypto will - * return OEMCrypto_ERROR_KEY_EXPIRED. - * 4) The content_key_data decrypted using the entitlement_key_data as a key - * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is - * padded using PKCS#7 padding. Notice that the entitlement key will be an - * AES 256 bit key. The clear content key data will be stored in the - * entry’s content_key_data. - * 5) The decrypted content key data may be set in a hardware KeySlot, - * together with content iv and cipher mode information, which can be used - * by the Descrambler in TunerHal. The entitled key session ID may be used - * as the key token to uniquely identify the content key in KeySlot. - * - * @param[in] session: handle for the entitled key session to be used. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] even_key: key update for the even ecm key. May be null if the key - * does not change. - * @param[in] odd_key: key update for the odd ecm key. May be null if the key - * does not change. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_KEY_NOT_ENTITLED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * @retval OEMCrypto_ERROR_KEY_EXPIRED - * @retval OEMCrypto_ERROR_ANALOG_OUTPUT - * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_LoadCasECMKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key); - /* * OEMCrypto_OPK_SerializationVersion + * + * Note: This is an undocumented function. It is only required and used by the + * OPK implementation of OEMCrypto. It is not in a documentation group and does + * not show up on the devsite documentation page. + * * Check the serialization protocol version used by the OEMCrypto Porting Kit * (OPK). If the OPK is not used, this function must return * OEMCrypto_ERROR_NOT_IMPLEMENTED. The serialization version is expressed as @@ -5518,6 +5555,110 @@ OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); * help with backward compatibility. */ OEMCryptoResult OEMCrypto_RemoveSRM(void); + +/** + * OEMCrypto_LoadKeys + * @deprecated + * OEMCrypto_LoadKeys is only used to load a v15 license or renewal. + */ +OEMCryptoResult OEMCrypto_LoadKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t key_array_length, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type); + +typedef struct { + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; +} OEMCrypto_KeyRefreshObject; +/** + * OEMCrypto_RefreshKeys + * @deprecated + * OEMCrypto_RefreshKeys is only used to load a v15 license or renewal. + */ +OEMCryptoResult OEMCrypto_RefreshKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, size_t num_keys, + const OEMCrypto_KeyRefreshObject* key_array); + +/** + * OEMCrypto_GetRandom + * @deprecated + * OEMCrypto_GetRandom is not needed to export random numbers. + */ +OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, + size_t random_data_length); + +/** + * OEMCrypto_SelectKey + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode); + +/** + * OEMCrypto_DecryptCENC_V17 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_DecryptCENC_V17( + OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, + size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern); + +/** + * OEMCrypto_Generic_Encrypt_V17 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_Generic_Encrypt_V17( + OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); + +/** + * OEMCrypto_Generic_Decrypt_V17 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_Generic_Decrypt_V17( + OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); + +/** + * OEMCrypto_Generic_Sign_V17 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_Generic_Sign_V17(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* signature, + size_t* signature_length); + +/** + * OEMCrypto_Generic_Verify_V17 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_Generic_Verify_V17( + OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + const OEMCrypto_SharedMemory* signature, size_t signature_length); + /****************************************************************************/ /****************************************************************************/ diff --git a/oemcrypto/include/OEMCryptoCENCCommon.h b/oemcrypto/include/OEMCryptoCENCCommon.h deleted file mode 120000 index dd92964..0000000 --- a/oemcrypto/include/OEMCryptoCENCCommon.h +++ /dev/null @@ -1 +0,0 @@ -../../oemcrypto/odk/include/OEMCryptoCENCCommon.h \ No newline at end of file diff --git a/oemcrypto/include/OEMCryptoCENCCommon.h b/oemcrypto/include/OEMCryptoCENCCommon.h new file mode 100644 index 0000000..da01169 --- /dev/null +++ b/oemcrypto/include/OEMCryptoCENCCommon.h @@ -0,0 +1 @@ +#include "../../oemcrypto/odk/include/OEMCryptoCENCCommon.h" diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h index 014b8cc..69f64da 100644 --- a/oemcrypto/include/level3.h +++ b/oemcrypto/include/level3.h @@ -16,7 +16,6 @@ #include "OEMCryptoCENC.h" #include "level3_file_system.h" -#include "oemcrypto_adapter.h" namespace wvoec3 { @@ -39,10 +38,10 @@ namespace wvoec3 { #define Level3_LoadDeviceRSAKey _lcc19 #define Level3_DeriveKeysFromSessionKey _lcc21 #define Level3_APIVersion _lcc22 -#define Level3_Generic_Encrypt _lcc24 -#define Level3_Generic_Decrypt _lcc25 -#define Level3_Generic_Sign _lcc26 -#define Level3_Generic_Verify _lcc27 +#define Level3_Generic_Encrypt_V17 _lcc24 +#define Level3_Generic_Decrypt_V17 _lcc25 +#define Level3_Generic_Sign_V17 _lcc26 +#define Level3_Generic_Verify_V17 _lcc27 #define Level3_SupportsUsageTable _lcc29 #define Level3_ReportUsage _lcc32 #define Level3_GetMaxNumberOfSessions _lcc37 @@ -88,7 +87,7 @@ namespace wvoec3 { #define Level3_LoadProvisioning _lcc102 #define Level3_LoadOEMPrivateKey _lcc103 #define Level3_GetOEMPublicCertificate _lcc104 -#define Level3_DecryptCENC _lcc105 +#define Level3_DecryptCENC_V17 _lcc105 #define Level3_LoadDRMPrivateKey _lcc107 #define Level3_MinorAPIVersion _lcc108 #define Level3_AllocateSecureBuffer _lcc109 @@ -109,6 +108,18 @@ namespace wvoec3 { #define Level3_ReuseUsageEntry _lcc127 #define Level3_GetDTCP2Capability _lcc128 #define Level3_GetWatermarkingSupport _lcc129 +#define Level3_GetOEMKeyToken _lcc130 +#define Level3_GetDeviceInformation _lcc131 +#define Level3_SetMaxAPIVersion _lcc132 +#define Level3_GetKeyHandle _lcc133 +#define Level3_DecryptCENC _lcc134 +#define Level3_Generic_Encrypt _lcc135 +#define Level3_Generic_Decrypt _lcc136 +#define Level3_Generic_Sign _lcc137 +#define Level3_Generic_Verify _lcc138 +#define Level3_GetSignatureHashAlgorithm _lcc139 +#define Level3_EnterTestMode _lcc140 +#define Level3_GetDeviceSignedCsrPayload _lcc141 #else #define Level3_Initialize _oecc01 #define Level3_Terminate _oecc02 @@ -126,10 +137,10 @@ namespace wvoec3 { #define Level3_LoadDeviceRSAKey _oecc19 #define Level3_DeriveKeysFromSessionKey _oecc21 #define Level3_APIVersion _oecc22 -#define Level3_Generic_Encrypt _oecc24 -#define Level3_Generic_Decrypt _oecc25 -#define Level3_Generic_Sign _oecc26 -#define Level3_Generic_Verify _oecc27 +#define Level3_Generic_Encrypt_V17 _oecc24 +#define Level3_Generic_Decrypt_V17 _oecc25 +#define Level3_Generic_Sign_V17 _oecc26 +#define Level3_Generic_Verify_V17 _oecc27 #define Level3_SupportsUsageTable _oecc29 #define Level3_ReportUsage _oecc32 #define Level3_GenerateRSASignature _oecc36 @@ -177,7 +188,7 @@ namespace wvoec3 { #define Level3_LoadProvisioning _oecc102 #define Level3_LoadOEMPrivateKey _oecc103 #define Level3_GetOEMPublicCertificate _oecc104 -#define Level3_DecryptCENC _oecc105 +#define Level3_DecryptCENC_V17 _oecc105 #define Level3_LoadDRMPrivateKey _oecc107 #define Level3_MinorAPIVersion _oecc108 #define Level3_AllocateSecureBuffer _oecc109 @@ -198,6 +209,18 @@ namespace wvoec3 { #define Level3_ReuseUsageEntry _oecc127 #define Level3_GetDTCP2Capability _oecc128 #define Level3_GetWatermarkingSupport _oecc129 +#define Level3_GetOEMKeyToken _oecc130 +#define Level3_GetDeviceInformation _oecc131 +#define Level3_SetMaxAPIVersion _oecc132 +#define Level3_GetKeyHandle _oecc133 +#define Level3_DecryptCENC _oecc134 +#define Level3_Generic_Encrypt _oecc135 +#define Level3_Generic_Decrypt _oecc136 +#define Level3_Generic_Sign _oecc137 +#define Level3_Generic_Verify _oecc138 +#define Level3_GetSignatureHashAlgorithm _oecc139 +#define Level3_EnterTestMode _oecc140 +#define Level3_GetDeviceSignedCsrPayload _oecc141 #endif #define Level3_GetInitializationState _oecl3o01 @@ -222,7 +245,7 @@ OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session, size_t key_id_length, uint8_t* key_control_block, size_t* key_control_block_length); -OEMCryptoResult Level3_DecryptCENC( +OEMCryptoResult Level3_DecryptCENC_V17( OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern); OEMCryptoResult Level3_InstallKeyboxOrOEMCert(const uint8_t* rot, @@ -280,28 +303,24 @@ bool Level3_IsAntiRollbackHwPresent(); OEMCryptoResult Level3_GetNumberOfOpenSessions(size_t* count); OEMCryptoResult Level3_GetMaxNumberOfSessions(size_t* maximum); uint32_t Level3_SupportedCertificates(); -OEMCryptoResult Level3_Generic_Encrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer); -OEMCryptoResult Level3_Generic_Decrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer); -OEMCryptoResult Level3_Generic_Sign(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, - size_t* signature_length); -OEMCryptoResult Level3_Generic_Verify(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length); +OEMCryptoResult Level3_Generic_Encrypt_V17( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); +OEMCryptoResult Level3_Generic_Decrypt_V17( + OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer); +OEMCryptoResult Level3_Generic_Sign_V17(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + uint8_t* signature, + size_t* signature_length); +OEMCryptoResult Level3_Generic_Verify_V17(OEMCrypto_SESSION session, + const uint8_t* in_buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length); OEMCryptoResult Level3_DeactivateUsageEntry(OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length); @@ -424,6 +443,57 @@ OEMCryptoResult Level3_ReuseUsageEntry(OEMCrypto_SESSION session, OEMCryptoResult Level3_GetDTCP2Capability( OEMCrypto_DTCP2_Capability* capability); OEMCrypto_WatermarkingSupport Level3_GetWatermarkingSupport(); +OEMCryptoResult Level3_GetOEMKeyToken(OEMCrypto_SESSION key_session, + uint8_t* key_token, + size_t* key_token_length); +OEMCryptoResult Level3_GetDeviceInformation(uint8_t* device_info, + size_t* device_info_length); +OEMCryptoResult Level3_GetDeviceSignedCsrPayload( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + uint8_t* signed_csr_payload, size_t* signed_csr_payload_length); +OEMCryptoResult Level3_SetMaxAPIVersion(uint32_t max_version); +OEMCryptoResult Level3_GetKeyHandle(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, + uint8_t* key_handle, + size_t* key_handle_length); +OEMCryptoResult Level3_DecryptCENC( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern); +OEMCryptoResult Level3_Generic_Encrypt(const uint8_t* key_handle, + size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult Level3_Generic_Decrypt(const uint8_t* key_handle, + size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult Level3_Generic_Sign(const uint8_t* key_handle, + size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* signature, + size_t* signature_length); +OEMCryptoResult Level3_Generic_Verify(const uint8_t* key_handle, + size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, + OEMCrypto_Algorithm algorithm, + const OEMCrypto_SharedMemory* signature, + size_t signature_length); +OEMCryptoResult Level3_GetSignatureHashAlgorithm( + OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm); +OEMCryptoResult Level3_EnterTestMode(void); // The following are specific to Google's Level 3 implementation and are not // required. diff --git a/oemcrypto/odk/Android.bp b/oemcrypto/odk/Android.bp index 3b7d807..92646bc 100644 --- a/oemcrypto/odk/Android.bp +++ b/oemcrypto/odk/Android.bp @@ -14,6 +14,7 @@ package { // all of the 'license_kinds' from "vendor_widevine_license" // to get the below license kinds: // legacy_by_exception_only (by exception only) + // legacy_proprietary (by exception only) default_applicable_licenses: ["vendor_widevine_license"], } @@ -93,6 +94,10 @@ cc_test { "libwv_kdo", ], + shared_libs: [ + "libprotobuf-cpp-lite", + ], + srcs: [ "test/odk_test.cpp", "test/odk_test_helper.cpp", diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index ce51b8d..97989aa 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -106,6 +106,8 @@ typedef enum OEMCryptoResult { OPK_ERROR_REMOTE_CALL = OPK_ERROR_BASE, OPK_ERROR_INCOMPATIBLE_VERSION = OPK_ERROR_BASE + 1, OPK_ERROR_NO_PERSISTENT_DATA = OPK_ERROR_BASE + 2, + OPK_ERROR_PREHOOK_FAILURE = OPK_ERROR_BASE + 3, + OPK_ERROR_POSTHOOK_FAILURE = OPK_ERROR_BASE + 4, } OEMCryptoResult; /* clang-format on */ @@ -139,8 +141,20 @@ typedef enum OEMCrypto_LicenseType { typedef enum OEMCrypto_PrivateKeyType { OEMCrypto_RSA_Private_Key = 0, OEMCrypto_ECC_Private_Key = 1, + OEMCrypto_PrivateKeyType_MaxValue = OEMCrypto_ECC_Private_Key, } OEMCrypto_PrivateKeyType; +/** + * The base for (delayed) timers, i.e. from what time the (delayed) timer + * starts. + */ +typedef enum OEMCrypto_TimerDelayBase { + OEMCrypto_License_Start = 0, + OEMCrypto_License_Load = 1, + OEMCrypto_First_Decrypt = 2, + OEMCrypto_TimerDelayBase_MaxValue = OEMCrypto_First_Decrypt, +} OEMCrypto_TimerDelayBase; + /** * Used to indicate a substring of a signed message in OEMCrypto_LoadKeys and * other functions which must verify that a parameter is contained within a diff --git a/oemcrypto/odk/include/core_message_deserialize.h b/oemcrypto/odk/include/core_message_deserialize.h index 545a806..a52c5fd 100644 --- a/oemcrypto/odk/include/core_message_deserialize.h +++ b/oemcrypto/odk/include/core_message_deserialize.h @@ -55,6 +55,18 @@ bool CoreProvisioningRequestFromMessage( const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request); +/** + * Counterpart (deserializer) of ODK_PrepareCoreProvisioning40Request + * (serializer) + * + * Parameters: + * [in] oemcrypto_core_message + * [out] core_provisioning_request + */ +bool CoreProvisioning40RequestFromMessage( + const std::string& oemcrypto_core_message, + ODK_Provisioning40Request* core_provisioning_request); + /** * Counterpart (deserializer) of ODK_PrepareCoreRenewedProvisioningRequest * (serializer) diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h index 16289c6..6e210d6 100644 --- a/oemcrypto/odk/include/core_message_features.h +++ b/oemcrypto/odk/include/core_message_features.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace oemcrypto_core_message { @@ -25,10 +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 16.5, the last version used by Chrome. This will - // change to 17.0 when v17 has been released. + // number. The default is 17.2. uint32_t maximum_major_version = 17; - uint32_t maximum_minor_version = 0; + uint32_t maximum_minor_version = 2; bool operator==(const CoreMessageFeatures &other) const; bool operator!=(const CoreMessageFeatures &other) const { diff --git a/oemcrypto/odk/include/core_message_serialize.h b/oemcrypto/odk/include/core_message_serialize.h index bd6d635..765d292 100644 --- a/oemcrypto/odk/include/core_message_serialize.h +++ b/oemcrypto/odk/include/core_message_serialize.h @@ -72,6 +72,21 @@ bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, const ODK_ParsedProvisioning& parsed_prov, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message); + +/** + * Counterpart (serializer) of ODK_ParseProvisioning40 (deserializer) + * struct-input variant + * + * Parameters: + * [in] features feature support for response message. + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreProvisioning40Response( + const CoreMessageFeatures& features, + const ODK_Provisioning40Request& core_request, + std::string* oemcrypto_core_message); + } // namespace serialize } // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/include/core_message_serialize_proto.h b/oemcrypto/odk/include/core_message_serialize_proto.h index de75362..73d7b73 100644 --- a/oemcrypto/odk/include/core_message_serialize_proto.h +++ b/oemcrypto/odk/include/core_message_serialize_proto.h @@ -17,6 +17,7 @@ #include #include +#include "OEMCryptoCENCCommon.h" #include "core_message_features.h" #include "core_message_types.h" #include "license_protocol.pb.h" @@ -42,8 +43,8 @@ bool CreateCoreLicenseResponseFromProto( const oemcrypto_core_message::features::CoreMessageFeatures& features, const std::string& serialized_license, const ODK_LicenseRequest& core_request, - const std::string& core_request_sha256, const bool nonce_required, - const bool uses_padding, std::string* oemcrypto_core_message); + const std::string& core_request_sha256, bool nonce_required, + bool uses_padding, std::string* oemcrypto_core_message); /** * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) @@ -59,6 +60,7 @@ bool CreateCoreProvisioningResponseFromProto( const oemcrypto_core_message::features::CoreMessageFeatures& features, const std::string& serialized_provisioning_response, const ODK_ProvisioningRequest& core_request, + OEMCrypto_PrivateKeyType device_key_type, std::string* oemcrypto_core_message); } // namespace serialize diff --git a/oemcrypto/odk/include/core_message_types.h b/oemcrypto/odk/include/core_message_types.h index 5315913..d268aef 100644 --- a/oemcrypto/odk/include/core_message_types.h +++ b/oemcrypto/odk/include/core_message_types.h @@ -30,23 +30,25 @@ * KDO provides a corresponding writer. * * Table: ODK vs KDO (s: serialize; d: deserialize) - * +----------------------------------------+---------------------------------------+ - * | ODK | KDO | - * +---+------------------------------------+---+-----------------------------------+ - * | s | ODK_PrepareCoreLicenseRequest | d | CoreLicenseRequestFromMessage | - * | +------------------------------------+ +-----------------------------------+ - * | | ODK_PrepareCoreRenewalRequest | | CoreRenewalRequestFromMessage | - * | +------------------------------------+ +-----------------------------------+ - * | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage| - * | +------------------------------------+ +-----------------------------------+ - * | | ODK_PrepareCommonRequest | | CoreCommonRequestFromMessage | - * +---+------------------------------------+---+-----------------------------------+ - * | d | ODK_ParseLicense | s | CreateCoreLicenseResponse | - * | +------------------------------------+ +-----------------------------------+ - * | | ODK_ParseRenewal | | CreateCoreRenewalResponse | - * | +------------------------------------+ +-----------------------------------+ - * | | ODK_ParseProvisioning | | CreateCoreProvisioningResponse | - * +---+------------------------------------+---+-----------------------------------+ + * +------------------------------------------+------------------------------------------+ + * | ODK | KDO | + * +---+--------------------------------------+---+--------------------------------------+ + * | s | ODK_PrepareCoreLicenseRequest | d | CoreLicenseRequestFromMessage | + * | +--------------------------------------+ +--------------------------------------+ + * | | ODK_PrepareCoreRenewalRequest | | CoreRenewalRequestFromMessage | + * | +--------------------------------------+ +--------------------------------------+ + * | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage | + * | | ODK_PrepareCoreProvisioning40Request | | CoreProvisioning40RequestFromMessage | + * | +--------------------------------------+ +--------------------------------------+ + * | | ODK_PrepareCommonRequest | | CoreCommonRequestFromMessage | + * +---+--------------------------------------+---+--------------------------------------+ + * | d | ODK_ParseLicense | s | CreateCoreLicenseResponse | + * | +--------------------------------------+ +--------------------------------------+ + * | | ODK_ParseRenewal | | CreateCoreRenewalResponse | + * | +--------------------------------------+ +--------------------------------------+ + * | | ODK_ParseProvisioning | | CreateCoreProvisioningResponse | + * | | ODK_ParseProvisioning40 | | CreateCoreProvisioning40Response | + * +---+--------------------------------------+---+--------------------------------------+ * *********************************************************************/ // clang-format on @@ -66,12 +68,27 @@ namespace oemcrypto_core_message { * Input structure for CreateCommonResponse */ struct ODK_CommonRequest { + uint32_t message_type; + uint32_t message_length; uint16_t api_minor_version; uint16_t api_major_version; uint32_t nonce; uint32_t session_id; }; +struct ODK_MessageCounter { + uint64_t master_generation_number; + uint32_t provisioning_count; + uint32_t license_count; + uint32_t decrypt_count; + uint16_t major_version; + uint16_t minor_version; + uint16_t patch_version; + uint8_t soc_vendor[16]; + uint8_t chipset_model[16]; + uint8_t extra[12]; +}; + /** * Output structure for CoreLicenseRequestFromMessage * Input structure for CreateCoreLicenseResponse @@ -81,6 +98,7 @@ struct ODK_LicenseRequest { uint16_t api_major_version; uint32_t nonce; uint32_t session_id; + ODK_MessageCounter counter_info; }; /** @@ -108,6 +126,20 @@ struct ODK_ProvisioningRequest { std::string device_id; uint16_t renewal_type; std::string renewal_data; + ODK_MessageCounter counter_info; +}; + +/** + * Output structure for CoreProvisioningRequest40FromMessage + * Input structure for CreateCoreProvisioning40Response + */ +struct ODK_Provisioning40Request { + uint16_t api_minor_version; + uint16_t api_major_version; + uint32_t nonce; + uint32_t session_id; + std::string device_info; + ODK_MessageCounter counter_info; }; } // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h index e3499da..16af94a 100644 --- a/oemcrypto/odk/include/odk.h +++ b/oemcrypto/odk/include/odk.h @@ -259,6 +259,8 @@ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values); * of the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in] message_count_info: information used for server-side anomaly + * detection * * @retval OEMCrypto_SUCCESS * @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small @@ -269,7 +271,8 @@ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values); */ OEMCryptoResult ODK_PrepareCoreLicenseRequest( uint8_t* message, size_t message_length, size_t* core_message_size, - const ODK_NonceValues* nonce_values); + const ODK_NonceValues* nonce_values, + const ODK_MessageCounterInfo* counter_info); /** * Modifies the message to include a core renewal request at the beginning of @@ -337,11 +340,8 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, * of the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * @param[in] nonce_values: pointer to the session's nonce data. - * @param[in] device_id: For devices with a keybox, this is the device ID from - * the keybox. For devices with an OEM Certificate, this is a device - * unique id string. - * @param[in] device_id_length: length of device_id. The device ID can be at - * most 64 bytes. + * @param[in] message_count_info: information used for server-side anomaly + * detection * * @retval OEMCrypto_SUCCESS * @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small @@ -352,8 +352,44 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, */ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_length, - const ODK_NonceValues* nonce_values, const uint8_t* device_id, - size_t device_id_length); + const ODK_NonceValues* nonce_values, + const ODK_MessageCounterInfo* counter_info); + +/** + * Modifies the message to include a core provisioning 4.0 request at the + * beginning of the message buffer. The values in nonce_values are used to + * populate the message. + * + * This shall be called by OEMCrypto from + * OEMCrypto_PrepAndSignProvisioningRequest. + * + * NOTE: if the message pointer is null and/or input core_message_length is + * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output + * core_message_size to the size needed. + * + * @param[in,out] message: Pointer to memory for the entire message. Modified by + * the ODK library. + * @param[in] message_length: length of the entire message buffer. + * @param[in,out] core_message_size: length of the core message at the beginning + * of the message. (in) size of buffer reserved for the core message, in + * bytes. (out) actual length of the core message, in bytes. + * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in] device_info: Encoded device hardware info in CBOR format. + * @param[in] device_info_length: length of device_info. + * @param[in] message_count_info: information used for server-side anomaly + * detection + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * + * @version + * This method is new in version 18 of the API. + */ +OEMCryptoResult ODK_PrepareCoreProvisioning40Request( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_info, + size_t device_info_length, const ODK_MessageCounterInfo* counter_info); /** * Modifies the message to include a core renewal provisioning request at the @@ -515,6 +551,7 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, * and false when called for OEMCrypto_ReloadLicense. * @param[in] usage_entry_present: true if the session has a new usage entry * associated with it created via OEMCrypto_CreateNewUsageEntry. + * @param[in] system_time_seconds: The current system's time in seconds. * @param[in,out] timer_limits: The session's timer limits. These will be * updated. * @param[in,out] clock_values: The session's clock values. These will be @@ -522,13 +559,19 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, * @param[in,out] nonce_values: The session's nonce values. These will be * updated. * @param[out] parsed_license: the destination for the data. + * @param[out] timer_value: set if playback timer should be started. * * @retval OEMCrypto_SUCCESS * @retval ODK_ERROR_CORE_MESSAGE: if the message did not parse correctly, or * there were other incorrect values. An error should be returned to the * CDM layer. * @retval ODK_UNSUPPORTED_API - * @retval OEMCrypto_ERROR_INVALID_NONCE + * @retval ODK_SET_TIMER: if the playback timer has been started successfully + * @retval ODK_DISABLE_TIMER: if the playtime timer has been started + * successfully then is disabled. + * @retval ODK_TIMER_EXPIRED: if the license is attempted to be loaded after the + * rental duration expires. + * @retval OEMCrypto_ERROR_INVALåID_NONCE * * @version * This method is new in version 16 of the API. @@ -536,8 +579,9 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, OEMCryptoResult ODK_ParseLicense( const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, - ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, - ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license); + uint64_t system_time_seconds, ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, + ODK_ParsedLicense* parsed_license, uint64_t* timer_value); /** * The function ODK_ParseRenewal will parse the message and verify its @@ -564,7 +608,8 @@ OEMCryptoResult ODK_ParseLicense( * @param[in] message_length: length of the entire message buffer. * @param[in] core_message_size: length of the core message, at the beginning of * the message buffer. - * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in,out] nonce_values: pointer to the session's nonce data. These might + * be updated if the server returns a lower API version. * @param[in] system_time_seconds: the current time on OEMCrypto's clock, in * seconds. * @param[in] timer_limits: timer limits specified in the license. @@ -591,7 +636,7 @@ OEMCryptoResult ODK_ParseLicense( */ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, size_t core_message_length, - const ODK_NonceValues* nonce_values, + ODK_NonceValues* nonce_values, uint64_t system_time_seconds, const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, @@ -604,8 +649,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, * If the message does not parse correctly, ODK_ParseProvisioning will return * an error that OEMCrypto should return to the CDM layer above. * - * If the API in the message is larger than 16, then ODK_UNSUPPORTED_API is - * returned. + * If the API in the message is larger than ODK_MAJOR_VERSION, then + * ODK_UNSUPPORTED_API is returned. * * ODK_ParseProvisioning shall verify that nonce_values->nonce and * nonce_values->session_id are the same as those in the message. Otherwise @@ -620,11 +665,13 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, * @param[in] message_length: length of the entire message buffer. * @param[in] core_message_size: length of the core message, at the beginning of * the message buffer. - * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in/out] nonce_values: pointer to the session's nonce data. These might + * be updated if the server returns a lower API version. * @param[in] device_id: a pointer to a buffer containing the device ID of the * device. The ODK function will verify it matches that in the message. * @param[in] device_id_length: the length of the device ID. - * @param[out] parsed_response: destination for the parse data. + * @param[out] counter_info: destination for counter portion of parse data. + * @param[out] parsed_response: destination for response portion of parse data. * * @retval OEMCrypto_SUCCESS * @retval ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there @@ -638,9 +685,45 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, */ OEMCryptoResult ODK_ParseProvisioning( const uint8_t* message, size_t message_length, size_t core_message_length, - const ODK_NonceValues* nonce_values, const uint8_t* device_id, + ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length, ODK_ParsedProvisioning* parsed_response); +/** + * The function ODK_ParseProvisioning40 will parse the message and verify the + * nonce values match those in the request. + * + * If the message does not parse correctly, ODK_ParseProvisioning40 will return + * an error that OEMCrypto should return to the CDM layer above. + * + * If the API in the message is larger than ODK_MAJOR_VERSION, then + * ODK_UNSUPPORTED_API is returned. + * + * ODK_ParseProvisioning40 shall verify that nonce_values->nonce and + * nonce_values->session_id are the same as those in the message. Otherwise + * it shall return OEMCrypto_ERROR_INVALID_NONCE. + * + * @param[in] message: pointer to the message buffer. + * @param[in] message_length: length of the entire message buffer. + * @param[in] core_message_size: length of the core message, at the beginning of + * the message buffer. + * @param[in,out] nonce_values: pointer to the session's nonce data. These might + * be updated if the server returns a lower API version. + * + * @retval OEMCrypto_SUCCESS + * @retval ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there + * were other incorrect values. An error should be returned to the CDM + * layer. + * @retval ODK_UNSUPPORTED_API + * @retval OEMCrypto_ERROR_INVALID_NONCE + * + * @version + * This method is new in version 18 of the API. + */ +OEMCryptoResult ODK_ParseProvisioning40(const uint8_t* message, + size_t message_length, + size_t core_message_length, + ODK_NonceValues* nonce_values); + /** * The function ODK_ParseProvisioning will parse the message and verify the * API version is at most the version passed in. diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h index 075f28c..cdbf26b 100644 --- a/oemcrypto/odk/include/odk_message.h +++ b/oemcrypto/odk/include/odk_message.h @@ -36,10 +36,12 @@ extern "C" { #if defined(__GNUC__) || defined(__clang__) #define ALIGNED __attribute__((aligned)) +#elif _MSC_VER +#define ALIGNED __declspec(align(8)) #else #define ALIGNED #error ODK_Message must be aligned to the maximum useful alignment of the \ - machine you are compiling for. Define the ALIGNED macro accordingly. + machine you are compiling for. Define the ALIGNED macro accordingly. #endif typedef struct { @@ -61,7 +63,8 @@ typedef enum { MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, MESSAGE_STATUS_OUT_OF_MEMORY = 0x7c5c64cc, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0x7afecacf, - MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 + MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873, + MESSAGE_STATUS_BUFFER_TOO_LARGE = 0x5bfcfb21 } ODK_MessageStatus; /* diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index fba3c3a..8a2b8ee 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -15,11 +15,11 @@ extern "C" { #include "odk_target.h" /* The version of this library. */ -#define ODK_MAJOR_VERSION 17 +#define ODK_MAJOR_VERSION 18 #define ODK_MINOR_VERSION 1 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v17.1 2022-06-17" +#define ODK_RELEASE_DATE "ODK v18.1 2023-02-25" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 @@ -28,6 +28,11 @@ extern "C" { #define ODK_DEVICE_ID_LEN_MAX 64 #define ODK_SHA256_HASH_SIZE 32 #define ODK_KEYBOX_RENEWAL_DATA_SIZE 1600 +/* The max length of the encoded device info in CBOR format. Make sure it gets + * updated when more device info is included. Refer to + * https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e + * for an estimation of the required length. */ +#define ODK_DEVICE_INFO_LEN_MAX 768 /// @addtogroup odk_timer /// @{ @@ -161,6 +166,47 @@ typedef struct { /// @addtogroup odk_parser /// @{ +/** + * This counter information is used by the license and provisioning servers to + * keep track of requests. Values should be updated after every successful + * provisioning request, license request, and decrypt call. + * + * @param provisioning_count: number of times a provisioning request was made on + * this device in the current instance. May be reset to 0 on device power off. + * @param license_count: number of times a license request was made on this + * device in the current instance. May be reset to 0 on device power off. + * @param decrypt_count: number of times OEMCrypto_DecryptCENC() has been called + * on this device in the current instance. May be reset to 0 on device power + * off. + * @param master_generation_number: current master generation number value from + * the OEMCrypto usage table. Persists across reboots. + * @param soc_vendor: name of the system-on-a-chip vendor for the device, + * limited to 16 bytes + * @param chipset_model: name of the chipset on the device, limited to 16 bytes + * @param major_version: major version of the TA binary. This is different from + * the OEMCrypto version that is being implemented. + * @param minor_version: minor version of the TA binary, if applicable. This is + * different from the OEMCrypto version that is being implemented. + * @param patch_version: patch version of the TA binary, if applicable. This is + * different from the OEMCrypto version that is being implemented. + * @param extra: unused in V18 + * + * @version + * This struct was added in API version 18. + */ +typedef struct { + uint64_t master_generation_number; + uint32_t provisioning_count; + uint32_t license_count; + uint32_t decrypt_count; + uint16_t major_version; + uint16_t minor_version; + uint16_t patch_version; + uint8_t soc_vendor[16]; + uint8_t chipset_model[16]; + uint8_t extra[12]; +} ODK_MessageCounterInfo; + /** * The parsed license structure contains information from the license * message. The function ODK_ParseLicense will fill in the fields of this @@ -178,11 +224,12 @@ typedef struct { * @param timer_limits: time limits of the for the license. * @param watermarking: specifies if device supports watermarking. * @param dtcp2_required: specifies if device supports DTCP. + * @param renewal_delay_base: what time the timer starting is based off of. * @param key_array_length: number of keys present. * @param key_array: set of keys to be installed. * * @version - * This struct changed in API version 17. + * This struct changed in API version 18. */ typedef struct { OEMCrypto_Substring enc_mac_keys_iv; @@ -194,6 +241,7 @@ typedef struct { ODK_TimerLimits timer_limits; uint32_t watermarking; OEMCrypto_DTCP2_CMI_Packet dtcp2_required; + OEMCrypto_TimerDelayBase renewal_delay_base; uint32_t key_array_length; OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS]; } ODK_ParsedLicense; diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp index 2e69641..5c8054f 100644 --- a/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -11,10 +11,10 @@ #include #include "OEMCryptoCENCCommon.h" +#include "odk_message.h" #include "odk_serialize.h" #include "odk_structs.h" #include "odk_structs_priv.h" -#include "serialization_base.h" namespace oemcrypto_core_message { namespace deserialize { @@ -89,12 +89,62 @@ bool ParseRequest(uint32_t message_type, } // namespace +static bool GetNonceFromMessage(const std::string& oemcrypto_core_message, + ODK_NonceValues* nonce_values) { + if (nonce_values == nullptr) return false; + if (oemcrypto_core_message.size() < sizeof(ODK_CoreMessage)) return false; + + ODK_CoreMessage core_message; + const uint8_t* buf = + reinterpret_cast(oemcrypto_core_message.c_str()); + ODK_Message msg = ODK_Message_Create(const_cast(buf), + oemcrypto_core_message.size()); + ODK_Message_SetSize(&msg, sizeof(ODK_CoreMessage)); + Unpack_ODK_CoreMessage(&msg, &core_message); + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) return false; + *nonce_values = core_message.nonce_values; + return true; +} + +bool CopyCounterInfo(ODK_MessageCounter* dest, ODK_MessageCounterInfo* src) { + if (!src || !dest) return false; + + dest->master_generation_number = src->master_generation_number; + dest->license_count = src->license_count; + dest->provisioning_count = src->provisioning_count; + dest->decrypt_count = src->decrypt_count; + dest->major_version = src->major_version; + dest->minor_version = src->minor_version; + dest->patch_version = src->patch_version; + memcpy(&dest->soc_vendor, &src->soc_vendor, sizeof(dest->soc_vendor)); + memcpy(&dest->chipset_model, &src->chipset_model, + sizeof(dest->chipset_model)); + memcpy(&dest->extra, &src->extra, sizeof(dest->extra)); + return true; +} + bool CoreLicenseRequestFromMessage(const std::string& oemcrypto_core_message, ODK_LicenseRequest* core_license_request) { + ODK_NonceValues nonce; + if (!GetNonceFromMessage(oemcrypto_core_message, &nonce)) return false; + if (nonce.api_major_version <= 17) { + const auto unpacker = Unpack_ODK_PreparedLicenseRequestV17; + ODK_PreparedLicenseRequestV17 prepared_license = {}; + return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, + core_license_request, &prepared_license, unpacker); + } const auto unpacker = Unpack_ODK_PreparedLicenseRequest; ODK_PreparedLicenseRequest prepared_license = {}; - return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, - core_license_request, &prepared_license, unpacker); + if (!ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, + core_license_request, &prepared_license, unpacker)) { + return false; + } + if (!CopyCounterInfo(&core_license_request->counter_info, + &prepared_license.counter_info)) { + return false; + } + + return true; } bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message, @@ -112,26 +162,100 @@ bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message, bool CoreProvisioningRequestFromMessage( const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request) { - const auto unpacker = Unpack_ODK_PreparedProvisioningRequest; - ODK_PreparedProvisioningRequest prepared_provision = {}; - if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message, + // We can't tell if V18 format or older. Need to partially parse in order + // to get the nonce values, which will tell us. + ODK_NonceValues nonce; + if (!GetNonceFromMessage(oemcrypto_core_message, &nonce)) return false; + + if (nonce.api_major_version == 18) { + // Proceed with V18 types + const auto unpacker = Unpack_ODK_PreparedProvisioningRequest; + ODK_PreparedProvisioningRequest prepared_provision = {}; + if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message, + core_provisioning_request, &prepared_provision, + unpacker)) { + // check for edge case: initial v18 message which is 4 bytes smaller and + // has 0's in the message counter struct + const uint8_t* buf = + reinterpret_cast(oemcrypto_core_message.c_str()); + const size_t buf_length = oemcrypto_core_message.size(); + + if (!(buf_length + 4 == ODK_PROVISIONING_REQUEST_SIZE)) { + return false; + } + + // Expected zero padding. Size is the new ODK Provisioning Request (core + // message + const uint32_t + the rest) without the core message and const + // uint32_t. + uint8_t zeros[ODK_PROVISIONING_REQUEST_SIZE - 4 - ODK_CORE_MESSAGE_SIZE] = + {0}; + + // Compare zeros against the old Provisioning Request (core message + the + // rest). + if (memcmp(zeros, buf + ODK_CORE_MESSAGE_SIZE, sizeof(zeros)) != 0) { + return false; + } + + memset(&prepared_provision.counter_info, 0, + sizeof(prepared_provision.counter_info)); + } else if (!CopyCounterInfo(&core_provisioning_request->counter_info, + &prepared_provision.counter_info)) { + return false; + } + } else { + // V17 and older + const auto unpacker = Unpack_ODK_PreparedProvisioningRequestV17; + ODK_PreparedProvisioningRequestV17 prepared_provision = {}; + if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message, + core_provisioning_request, &prepared_provision, + unpacker)) { + return false; + } + const uint8_t* device_id = prepared_provision.device_id; + const uint32_t device_id_length = prepared_provision.device_id_length; + if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { + return false; + } + if (device_id_length > 0) { + uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {}; + if (memcmp(zero, device_id + device_id_length, + ODK_DEVICE_ID_LEN_MAX - device_id_length)) { + return false; + } + core_provisioning_request->device_id.assign( + reinterpret_cast(device_id), device_id_length); + } + core_provisioning_request->renewal_type = OEMCrypto_NoRenewal; + core_provisioning_request->renewal_data.clear(); + } + return true; +} + +bool CoreProvisioning40RequestFromMessage( + const std::string& oemcrypto_core_message, + ODK_Provisioning40Request* core_provisioning_request) { + const auto unpacker = Unpack_ODK_PreparedProvisioning40Request; + ODK_PreparedProvisioning40Request prepared_provision = {}; + if (!ParseRequest(ODK_Provisioning40_Request_Type, oemcrypto_core_message, core_provisioning_request, &prepared_provision, unpacker)) { return false; } - const uint8_t* device_id = prepared_provision.device_id; - const uint32_t device_id_length = prepared_provision.device_id_length; - if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { + if (!CopyCounterInfo(&core_provisioning_request->counter_info, + &prepared_provision.counter_info)) { return false; } - uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {}; - if (memcmp(zero, device_id + device_id_length, - ODK_DEVICE_ID_LEN_MAX - device_id_length)) { + const uint8_t* device_info = prepared_provision.device_info; + const uint32_t device_info_length = prepared_provision.device_info_length; + if (device_info_length > ODK_DEVICE_INFO_LEN_MAX) { return false; } - core_provisioning_request->device_id.assign( - reinterpret_cast(device_id), device_id_length); - core_provisioning_request->renewal_type = OEMCrypto_NoRenewal; - core_provisioning_request->renewal_data.clear(); + uint8_t zero[ODK_DEVICE_INFO_LEN_MAX] = {}; + if (memcmp(zero, device_info + device_info_length, + ODK_DEVICE_INFO_LEN_MAX - device_info_length)) { + return false; + } + core_provisioning_request->device_info.assign( + reinterpret_cast(device_info), device_info_length); return true; } @@ -173,8 +297,16 @@ bool CoreCommonRequestFromMessage(const std::string& oemcrypto_core_message, ODK_CommonRequest* common_request) { const auto unpacker = Unpack_ODK_PreparedCommonRequest; ODK_PreparedCommonRequest prepared_common = {}; - return ParseRequest(ODK_Common_Request_Type, oemcrypto_core_message, - common_request, &prepared_common, unpacker); + const bool success = + ParseRequest(ODK_Common_Request_Type, oemcrypto_core_message, + common_request, &prepared_common, unpacker); + + if (success) { + const auto& core_message = prepared_common.core_message; + common_request->message_type = core_message.message_type; + common_request->message_length = core_message.message_length; + } + return success; } } // namespace deserialize diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp index 615e477..b8bcb9e 100644 --- a/oemcrypto/odk/src/core_message_features.cpp +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -4,6 +4,8 @@ #include "core_message_features.h" +#include + namespace oemcrypto_core_message { namespace features { const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures; @@ -23,7 +25,10 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( features.maximum_minor_version = 5; // 16.5 break; case 17: - features.maximum_minor_version = 1; // 17.1 + features.maximum_minor_version = 2; // 17.2 + break; + case 18: + features.maximum_minor_version = 1; // 18.0 break; default: features.maximum_minor_version = 0; diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp index 3c3590e..8f28a3f 100644 --- a/oemcrypto/odk/src/core_message_serialize.cpp +++ b/oemcrypto/odk/src/core_message_serialize.cpp @@ -30,8 +30,9 @@ namespace { */ template bool CreateResponseHeader(const CoreMessageFeatures& features, - ODK_MessageType message_type, const S& core_request, - T& response) { + ODK_MessageType message_type, + ODK_CoreMessage* response_header, + const S& core_request, T& response) { // Bad major version. if ((features.maximum_major_version > ODK_MAJOR_VERSION) || (features.maximum_major_version == ODK_MAJOR_VERSION && @@ -40,20 +41,24 @@ bool CreateResponseHeader(const CoreMessageFeatures& features, return false; } - auto* header = &response.request.core_message; - header->message_type = message_type; - header->nonce_values.api_major_version = core_request.api_major_version; - header->nonce_values.api_minor_version = core_request.api_minor_version; - header->nonce_values.nonce = core_request.nonce; - header->nonce_values.session_id = core_request.session_id; + response_header->message_type = message_type; + response_header->nonce_values.api_major_version = + core_request.api_major_version; + response_header->nonce_values.api_minor_version = + core_request.api_minor_version; + response_header->nonce_values.nonce = core_request.nonce; + response_header->nonce_values.session_id = core_request.session_id; // The message API version for the response is the minimum of our version and // the request's version. if (core_request.api_major_version > features.maximum_major_version) { - header->nonce_values.api_major_version = features.maximum_major_version; - header->nonce_values.api_minor_version = features.maximum_minor_version; + response_header->nonce_values.api_major_version = + features.maximum_major_version; + response_header->nonce_values.api_minor_version = + features.maximum_minor_version; } else if (core_request.api_major_version == features.maximum_major_version && core_request.api_minor_version > features.maximum_minor_version) { - header->nonce_values.api_minor_version = features.maximum_minor_version; + response_header->nonce_values.api_minor_version = + features.maximum_minor_version; } return true; } @@ -68,14 +73,14 @@ bool CreateResponseHeader(const CoreMessageFeatures& features, */ template bool CreateResponse(ODK_MessageType message_type, const S& core_request, - std::string* oemcrypto_core_message, T& response, + std::string* oemcrypto_core_message, + ODK_CoreMessage* response_header, T& response, const P& packer) { if (!oemcrypto_core_message) { return false; } - auto* header = &response.request.core_message; - if (header->message_type != message_type || - header->nonce_values.api_major_version < ODK_FIRST_VERSION) { + if (response_header->message_type != message_type || + response_header->nonce_values.api_major_version < ODK_FIRST_VERSION) { // This indicates CreateResponseHeader was not called. return false; } @@ -89,8 +94,8 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request, } uint32_t message_length = static_cast(ODK_Message_GetSize(&msg)); - msg = ODK_Message_Create(buf.data() + sizeof(header->message_type), - sizeof(header->message_length)); + msg = ODK_Message_Create(buf.data() + sizeof(response_header->message_type), + sizeof(response_header->message_length)); Pack_uint32_t(&msg, &message_length); oemcrypto_core_message->assign(reinterpret_cast(buf.data()), message_length); @@ -98,10 +103,10 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request, } bool CopyDeviceId(const ODK_ProvisioningRequest& src, - ODK_ProvisioningResponse* dest) { + ODK_ProvisioningResponseV16* dest) { auto& request = dest->request; const std::string& device_id = src.device_id; - if (request.device_id_length > sizeof(request.device_id)) { + if (device_id.size() > sizeof(request.device_id)) { return false; } request.device_id_length = static_cast(device_id.size()); @@ -119,17 +124,17 @@ bool CreateCoreLicenseResponse(const CoreMessageFeatures& features, std::string* oemcrypto_core_message) { ODK_LicenseResponse license_response{ {}, const_cast(&parsed_lic)}; - if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request, + if (!CreateResponseHeader(features, ODK_License_Response_Type, + &license_response.core_message, core_request, license_response)) { return false; } if (ODK_MAX_NUM_KEYS < license_response.parsed_license->key_array_length) { return false; } - if (license_response.request.core_message.nonce_values.api_major_version == - 16) { + if (license_response.core_message.nonce_values.api_major_version == 16) { ODK_LicenseResponseV16 license_response_v16; - license_response_v16.request = license_response.request; + license_response_v16.request.core_message = license_response.core_message; license_response_v16.parsed_license.enc_mac_keys_iv = license_response.parsed_license->enc_mac_keys_iv; license_response_v16.parsed_license.enc_mac_keys = @@ -158,12 +163,73 @@ bool CreateCoreLicenseResponse(const CoreMessageFeatures& features, memcpy(license_response_v16.request_hash, core_request_sha256.data(), sizeof(license_response_v16.request_hash)); return CreateResponse(ODK_License_Response_Type, core_request, - oemcrypto_core_message, license_response_v16, - Pack_ODK_LicenseResponseV16); + oemcrypto_core_message, + &license_response_v16.request.core_message, + license_response_v16, Pack_ODK_LicenseResponseV16); + } else if (license_response.core_message.nonce_values.api_major_version == + 17) { + ODK_LicenseResponseV17 license_response_v17; + ODK_ParsedLicenseV17* dest = &license_response_v17.parsed_license; + ODK_ParsedLicense src = *license_response.parsed_license; + license_response_v17.request.core_message = license_response.core_message; + dest->enc_mac_keys_iv = src.enc_mac_keys_iv; + dest->enc_mac_keys = src.enc_mac_keys; + dest->pst = src.pst; + dest->srm_restriction_data = src.srm_restriction_data; + dest->license_type = src.license_type; + dest->nonce_required = src.nonce_required; + dest->timer_limits = src.timer_limits; + dest->watermarking = src.watermarking; + dest->dtcp2_required.dtcp2_required = src.dtcp2_required.dtcp2_required; + dest->dtcp2_required.cmi_descriptor_0.id = + src.dtcp2_required.cmi_descriptor_0.id; + dest->dtcp2_required.cmi_descriptor_0.extension = + src.dtcp2_required.cmi_descriptor_0.extension; + dest->dtcp2_required.cmi_descriptor_0.length = + src.dtcp2_required.cmi_descriptor_0.length; + dest->dtcp2_required.cmi_descriptor_0.data = + src.dtcp2_required.cmi_descriptor_0.data; + dest->dtcp2_required.cmi_descriptor_1.id = + src.dtcp2_required.cmi_descriptor_1.id; + dest->dtcp2_required.cmi_descriptor_1.extension = + src.dtcp2_required.cmi_descriptor_1.extension; + dest->dtcp2_required.cmi_descriptor_1.length = + src.dtcp2_required.cmi_descriptor_1.length; + dest->dtcp2_required.cmi_descriptor_1.data[0] = + src.dtcp2_required.cmi_descriptor_1.data[0]; + dest->dtcp2_required.cmi_descriptor_1.data[1] = + src.dtcp2_required.cmi_descriptor_1.data[1]; + dest->dtcp2_required.cmi_descriptor_1.data[2] = + src.dtcp2_required.cmi_descriptor_1.data[2]; + dest->dtcp2_required.cmi_descriptor_2.id = + src.dtcp2_required.cmi_descriptor_2.id; + dest->dtcp2_required.cmi_descriptor_2.extension = + src.dtcp2_required.cmi_descriptor_2.extension; + dest->dtcp2_required.cmi_descriptor_2.length = + src.dtcp2_required.cmi_descriptor_2.length; + dest->dtcp2_required.cmi_descriptor_2.data[0] = + src.dtcp2_required.cmi_descriptor_2.data[0]; + dest->dtcp2_required.cmi_descriptor_2.data[1] = + src.dtcp2_required.cmi_descriptor_2.data[1]; + dest->dtcp2_required.cmi_descriptor_2.data[2] = + src.dtcp2_required.cmi_descriptor_2.data[2]; + dest->key_array_length = src.key_array_length; + uint32_t i; + for (i = 0; i < dest->key_array_length && i < src.key_array_length; i++) { + dest->key_array[i] = src.key_array[i]; + } + if (core_request_sha256.size() != sizeof(license_response_v17.request_hash)) + return false; + memcpy(license_response_v17.request_hash, core_request_sha256.data(), + sizeof(license_response_v17.request_hash)); + return CreateResponse(ODK_License_Response_Type, core_request, + oemcrypto_core_message, + &license_response_v17.request.core_message, + license_response_v17, Pack_ODK_LicenseResponseV17); } return CreateResponse(ODK_License_Response_Type, core_request, - oemcrypto_core_message, license_response, - Pack_ODK_LicenseResponse); + oemcrypto_core_message, &license_response.core_message, + license_response, Pack_ODK_LicenseResponse); } bool CreateCoreRenewalResponse(const CoreMessageFeatures& features, @@ -173,13 +239,15 @@ bool CreateCoreRenewalResponse(const CoreMessageFeatures& features, ODK_RenewalResponse renewal_response{{}, core_request.playback_time_seconds}; renewal_response.request.playback_time = core_request.playback_time_seconds; renewal_response.renewal_duration_seconds = renewal_duration_seconds; - if (!CreateResponseHeader(features, ODK_Renewal_Response_Type, core_request, - renewal_response)) { + if (!CreateResponseHeader(features, ODK_Renewal_Response_Type, + &renewal_response.request.core_message, + core_request, renewal_response)) { return false; } return CreateResponse(ODK_Renewal_Response_Type, core_request, - oemcrypto_core_message, renewal_response, - Pack_ODK_RenewalResponse); + oemcrypto_core_message, + &renewal_response.request.core_message, + renewal_response, Pack_ODK_RenewalResponse); } bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, @@ -188,16 +256,43 @@ bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, std::string* oemcrypto_core_message) { ODK_ProvisioningResponse prov_response{ {}, const_cast(&parsed_prov)}; - if (!CopyDeviceId(core_request, &prov_response)) { + if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type, + &prov_response.core_message, core_request, + prov_response)) { return false; } + + if (prov_response.core_message.nonce_values.api_major_version <= 17) { + ODK_ProvisioningResponseV16 prov_response_v16; + if (!CopyDeviceId(core_request, &prov_response_v16)) { + return false; + } + prov_response_v16.request.core_message = prov_response.core_message; + prov_response_v16.parsed_provisioning = prov_response.parsed_provisioning; + return CreateResponse(ODK_Provisioning_Response_Type, core_request, + oemcrypto_core_message, + &prov_response_v16.request.core_message, + prov_response_v16, Pack_ODK_ProvisioningResponseV16); + } + + return CreateResponse(ODK_Provisioning_Response_Type, core_request, + oemcrypto_core_message, &prov_response.core_message, + prov_response, Pack_ODK_ProvisioningResponse); +} + +bool CreateCoreProvisioning40Response( + const CoreMessageFeatures& features, + const ODK_Provisioning40Request& core_request, + std::string* oemcrypto_core_message) { + ODK_Provisioning40Response prov_response = {}; if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type, - core_request, prov_response)) { + &prov_response.core_message, core_request, + prov_response)) { return false; } return CreateResponse(ODK_Provisioning_Response_Type, core_request, - oemcrypto_core_message, prov_response, - Pack_ODK_ProvisioningResponse); + oemcrypto_core_message, &prov_response.core_message, + prov_response, Pack_ODK_Provisioning40Response); } } // namespace serialize diff --git a/oemcrypto/odk/src/core_message_serialize_proto.cpp b/oemcrypto/odk/src/core_message_serialize_proto.cpp index 5132bda..78b20fb 100644 --- a/oemcrypto/odk/src/core_message_serialize_proto.cpp +++ b/oemcrypto/odk/src/core_message_serialize_proto.cpp @@ -164,19 +164,16 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features, core_request_sha256, oemcrypto_core_message); } -bool CreateCoreProvisioningResponseFromProto( - const CoreMessageFeatures& features, +bool DeserializeProvisioningResponse( const std::string& serialized_provisioning_resp, - const ODK_ProvisioningRequest& core_request, - std::string* oemcrypto_core_message) { - ODK_ParsedProvisioning parsed_prov{}; + const OEMCrypto_PrivateKeyType device_key_type, + ODK_ParsedProvisioning& parsed_prov) { video_widevine::ProvisioningResponse prov; if (!prov.ParseFromString(serialized_provisioning_resp)) { return false; } - parsed_prov.key_type = - OEMCrypto_RSA_Private_Key; // TODO(b/148404408): ECC or RSA + parsed_prov.key_type = device_key_type; if (prov.has_device_rsa_key()) { parsed_prov.enc_private_key = GetOecSubstring(serialized_provisioning_resp, prov.device_rsa_key()); @@ -189,7 +186,19 @@ bool CreateCoreProvisioningResponseFromProto( parsed_prov.encrypted_message_key = GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key()); } + return true; +} +bool CreateCoreProvisioningResponseFromProto( + const CoreMessageFeatures& features, + const std::string& serialized_provisioning_resp, + const ODK_ProvisioningRequest& core_request, + const OEMCrypto_PrivateKeyType device_key_type, + std::string* oemcrypto_core_message) { + ODK_ParsedProvisioning parsed_prov{}; + if (!DeserializeProvisioningResponse(serialized_provisioning_resp, + device_key_type, parsed_prov)) + return false; return CreateCoreProvisioningResponse(features, parsed_prov, core_request, oemcrypto_core_message); } diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index 4f28389..db6f510 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "odk_overflow.h" @@ -13,7 +14,6 @@ #include "odk_structs.h" #include "odk_structs_priv.h" #include "odk_util.h" -#include "serialization_base.h" /* @ private odk functions */ @@ -31,7 +31,7 @@ static OEMCryptoResult ODK_PrepareRequest( /* The core message should be at the beginning of the buffer, and with a * shorter length. */ - if (sizeof(ODK_CoreMessage) > prepared_request_buffer_length) { + if (ODK_CORE_MESSAGE_SIZE > prepared_request_buffer_length) { return ODK_ERROR_CORE_MESSAGE; } ODK_CoreMessage* core_message = (ODK_CoreMessage*)prepared_request_buffer; @@ -72,6 +72,16 @@ static OEMCryptoResult ODK_PrepareRequest( &msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); break; } + case ODK_Provisioning40_Request_Type: { + core_message->message_length = ODK_PROVISIONING40_REQUEST_SIZE; + if (sizeof(ODK_PreparedProvisioning40Request) > + prepared_request_buffer_length) { + return ODK_ERROR_CORE_MESSAGE; + } + Pack_ODK_PreparedProvisioning40Request( + &msg, (ODK_PreparedProvisioning40Request*)prepared_request_buffer); + break; + } case ODK_Renewed_Provisioning_Request_Type: { core_message->message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE; if (sizeof(ODK_PreparedRenewedProvisioningRequest) > @@ -169,14 +179,18 @@ static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message, /* @@ prepare request functions */ OEMCryptoResult ODK_PrepareCoreLicenseRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - const ODK_NonceValues* nonce_values) { - if (core_message_length == NULL || nonce_values == NULL) { + uint8_t* message, size_t message_length, size_t* core_message_size, + const ODK_NonceValues* nonce_values, + const ODK_MessageCounterInfo* counter_info) { + if (core_message_size == NULL || nonce_values == NULL || + counter_info == NULL) { return ODK_ERROR_CORE_MESSAGE; } ODK_PreparedLicenseRequest license_request = {0}; + memcpy(&license_request.counter_info, counter_info, + sizeof(license_request.counter_info)); return ODK_PrepareRequest( - message, message_length, core_message_length, ODK_License_Request_Type, + message, message_length, core_message_size, ODK_License_Request_Type, nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest)); } @@ -230,25 +244,47 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, OEMCryptoResult ODK_PrepareCoreProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_length, - const ODK_NonceValues* nonce_values, const uint8_t* device_id, - size_t device_id_length) { - if (core_message_length == NULL || nonce_values == NULL) { + const ODK_NonceValues* nonce_values, + const ODK_MessageCounterInfo* counter_info) { + if (core_message_length == NULL || nonce_values == NULL || + counter_info == NULL) { return ODK_ERROR_CORE_MESSAGE; } ODK_PreparedProvisioningRequest provisioning_request = {0}; - if (device_id_length > sizeof(provisioning_request.device_id)) { - return ODK_ERROR_CORE_MESSAGE; - } - provisioning_request.device_id_length = (uint32_t)device_id_length; - if (device_id) { - memcpy(provisioning_request.device_id, device_id, device_id_length); - } + memcpy(&provisioning_request.counter_info, counter_info, + sizeof(ODK_MessageCounterInfo)); + return ODK_PrepareRequest(message, message_length, core_message_length, ODK_Provisioning_Request_Type, nonce_values, &provisioning_request, sizeof(ODK_PreparedProvisioningRequest)); } +OEMCryptoResult ODK_PrepareCoreProvisioning40Request( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_info, + size_t device_info_length, const ODK_MessageCounterInfo* counter_info) { + if (core_message_length == NULL || nonce_values == NULL || + counter_info == NULL) { + return ODK_ERROR_CORE_MESSAGE; + } + ODK_PreparedProvisioning40Request provisioning_request = {0}; + if (device_info_length > sizeof(provisioning_request.device_info)) { + return ODK_ERROR_CORE_MESSAGE; + } + provisioning_request.device_info_length = (uint32_t)device_info_length; + if (device_info) { + memcpy(provisioning_request.device_info, device_info, device_info_length); + } + memcpy(&provisioning_request.counter_info, counter_info, + sizeof(provisioning_request.counter_info)); + + return ODK_PrepareRequest(message, message_length, core_message_length, + ODK_Provisioning40_Request_Type, nonce_values, + &provisioning_request, + sizeof(provisioning_request)); +} + OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_length, const ODK_NonceValues* nonce_values, const uint8_t* device_id, @@ -285,14 +321,15 @@ OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest( OEMCryptoResult ODK_ParseLicense( const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, - ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, - ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license) { + uint64_t system_time_seconds, ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, + ODK_ParsedLicense* parsed_license, uint64_t* timer_value) { if (message == NULL || timer_limits == NULL || clock_values == NULL || nonce_values == NULL || parsed_license == NULL) { return ODK_ERROR_CORE_MESSAGE; } - const OEMCryptoResult err = + OEMCryptoResult err = ODK_ParseCoreHeader(message, message_length, core_message_length, ODK_License_Response_Type, nonce_values); if (err != OEMCrypto_SUCCESS) { @@ -303,6 +340,7 @@ OEMCryptoResult ODK_ParseLicense( license_response.parsed_license = parsed_license; ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); if (nonce_values->api_major_version == 16) { ODK_LicenseResponseV16 license_response_v16 = {0}; @@ -339,7 +377,6 @@ OEMCryptoResult ODK_ParseLicense( } // Set fields not used in V16 to default values. parsed_license->watermarking = 0; - // Set fields not used in V16 to default values. parsed_license->dtcp2_required.dtcp2_required = 0; parsed_license->dtcp2_required.cmi_descriptor_0.id = 0; parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0; @@ -357,7 +394,73 @@ OEMCryptoResult ODK_ParseLicense( parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0; parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0; parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0; - license_response.request = license_response_v16.request; + license_response.core_message = license_response_v16.request.core_message; + parsed_license->renewal_delay_base = 0; + } else if (nonce_values->api_major_version == 17) { + ODK_LicenseResponseV17 license_response_v17 = {0}; + Unpack_ODK_LicenseResponseV17(&msg, &license_response_v17); + + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + + ODK_ParsedLicenseV17 src = license_response_v17.parsed_license; + + // Need to manually set parsed_license fields to + // license_response_v17.parsed_license field values since + // license_response_v17 is no longer a pointer so parsed_license doesn't get + // updated during the unpacking. + parsed_license->enc_mac_keys_iv = src.enc_mac_keys_iv; + parsed_license->enc_mac_keys = src.enc_mac_keys; + parsed_license->pst = src.pst; + parsed_license->srm_restriction_data = src.srm_restriction_data; + parsed_license->license_type = src.license_type; + parsed_license->nonce_required = src.nonce_required; + parsed_license->timer_limits = src.timer_limits; + parsed_license->watermarking = src.watermarking; + parsed_license->dtcp2_required.dtcp2_required = + src.dtcp2_required.dtcp2_required; + parsed_license->dtcp2_required.cmi_descriptor_0.id = + src.dtcp2_required.cmi_descriptor_0.id; + parsed_license->dtcp2_required.cmi_descriptor_0.extension = + src.dtcp2_required.cmi_descriptor_0.extension; + parsed_license->dtcp2_required.cmi_descriptor_0.length = + src.dtcp2_required.cmi_descriptor_0.length; + parsed_license->dtcp2_required.cmi_descriptor_0.data = + src.dtcp2_required.cmi_descriptor_0.data; + parsed_license->dtcp2_required.cmi_descriptor_1.id = + src.dtcp2_required.cmi_descriptor_1.id; + parsed_license->dtcp2_required.cmi_descriptor_1.extension = + src.dtcp2_required.cmi_descriptor_1.extension; + parsed_license->dtcp2_required.cmi_descriptor_1.length = + src.dtcp2_required.cmi_descriptor_1.length; + parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = + src.dtcp2_required.cmi_descriptor_1.data[0]; + parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = + src.dtcp2_required.cmi_descriptor_1.data[1]; + parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = + src.dtcp2_required.cmi_descriptor_1.data[2]; + parsed_license->dtcp2_required.cmi_descriptor_2.id = + src.dtcp2_required.cmi_descriptor_2.id; + parsed_license->dtcp2_required.cmi_descriptor_2.extension = + src.dtcp2_required.cmi_descriptor_2.extension; + parsed_license->dtcp2_required.cmi_descriptor_2.length = + src.dtcp2_required.cmi_descriptor_2.length; + parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = + src.dtcp2_required.cmi_descriptor_2.data[0]; + parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = + src.dtcp2_required.cmi_descriptor_2.data[1]; + parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = + src.dtcp2_required.cmi_descriptor_2.data[2]; + parsed_license->key_array_length = src.key_array_length; + uint32_t i; + for (i = 0; i < parsed_license->key_array_length; i++) { + parsed_license->key_array[i] = src.key_array[i]; + } + // Set fields not used in V17 to default values. + parsed_license->renewal_delay_base = 0; + license_response.core_message = license_response_v17.request.core_message; } else { Unpack_ODK_LicenseResponse(&msg, &license_response); @@ -382,26 +485,32 @@ OEMCryptoResult ODK_ParseLicense( */ if (parsed_license->nonce_required && initial_license_load) { if (nonce_values->nonce != - license_response.request.core_message.nonce_values.nonce || + license_response.core_message.nonce_values.nonce || nonce_values->session_id != - license_response.request.core_message.nonce_values.session_id) { + license_response.core_message.nonce_values.session_id) { return OEMCrypto_ERROR_INVALID_NONCE; } } else { /* !initial_license_load, or can't tell if initial. */ - nonce_values->nonce = - license_response.request.core_message.nonce_values.nonce; + nonce_values->nonce = license_response.core_message.nonce_values.nonce; nonce_values->session_id = - license_response.request.core_message.nonce_values.session_id; + license_response.core_message.nonce_values.session_id; } + bool license_load = + (parsed_license->renewal_delay_base == OEMCrypto_License_Load); *timer_limits = parsed_license->timer_limits; /* And update the clock values state. */ clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED; + if (nonce_values->api_major_version == 18 && license_load) { + err = ODK_AttemptFirstPlayback(system_time_seconds, timer_limits, + clock_values, timer_value); + return err; + } return OEMCrypto_SUCCESS; } OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, size_t core_message_length, - const ODK_NonceValues* nonce_values, + ODK_NonceValues* nonce_values, uint64_t system_time, const ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, @@ -413,7 +522,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, const OEMCryptoResult err = ODK_ParseCoreHeader(message, message_length, core_message_length, - ODK_Renewal_Response_Type, NULL); + ODK_Renewal_Response_Type, nonce_values); if (err != OEMCrypto_SUCCESS) { return err; } @@ -454,7 +563,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, OEMCryptoResult ODK_ParseProvisioning( const uint8_t* message, size_t message_length, size_t core_message_length, - const ODK_NonceValues* nonce_values, const uint8_t* device_id, + ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length, ODK_ParsedProvisioning* parsed_response) { if (message == NULL || nonce_values == NULL || device_id == NULL || parsed_response == NULL) { @@ -462,44 +571,96 @@ OEMCryptoResult ODK_ParseProvisioning( } const OEMCryptoResult err = ODK_ParseCoreHeader(message, message_length, core_message_length, - ODK_Provisioning_Response_Type, NULL); + ODK_Provisioning_Response_Type, nonce_values); if (err != OEMCrypto_SUCCESS) { return err; } - ODK_ProvisioningResponse provisioning_response = {0}; - provisioning_response.parsed_provisioning = parsed_response; - if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { + if (nonce_values->api_major_version <= 17) { + // Do v16/v17 + ODK_ProvisioningResponseV16 provisioning_response = {0}; + provisioning_response.parsed_provisioning = parsed_response; + + if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { + return ODK_ERROR_CORE_MESSAGE; + } + + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); + Unpack_ODK_ProvisioningResponseV16(&msg, &provisioning_response); + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + /* always verify nonce_values for Renewal and Provisioning responses */ + if (!ODK_NonceValuesEqualExcludingVersion( + nonce_values, + &(provisioning_response.request.core_message.nonce_values))) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + + if (crypto_memcmp(device_id, provisioning_response.request.device_id, + device_id_length) != 0) { + return ODK_ERROR_CORE_MESSAGE; + } + + const uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {0}; + /* check bytes beyond device_id_length are 0 */ + if (crypto_memcmp( + zero, provisioning_response.request.device_id + device_id_length, + ODK_DEVICE_ID_LEN_MAX - device_id_length) != 0) { + return ODK_ERROR_CORE_MESSAGE; + } + } else { + // v18 + ODK_ProvisioningResponse provisioning_response = {0}; + provisioning_response.parsed_provisioning = parsed_response; + + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); + Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response); + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + /* always verify nonce_values for Renewal and Provisioning responses */ + if (!ODK_NonceValuesEqualExcludingVersion( + nonce_values, &(provisioning_response.core_message.nonce_values))) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + } + + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ODK_ParseProvisioning40(const uint8_t* message, + size_t message_length, + size_t core_message_length, + ODK_NonceValues* nonce_values) { + if (message == NULL || nonce_values == NULL) { return ODK_ERROR_CORE_MESSAGE; } + const OEMCryptoResult err = + ODK_ParseCoreHeader(message, message_length, core_message_length, + ODK_Provisioning_Response_Type, nonce_values); + if (err != OEMCrypto_SUCCESS) { + return err; + } + ODK_Provisioning40Response provisioning_response = {0}; ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); ODK_Message_SetSize(&msg, core_message_length); - Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response); + Unpack_ODK_Provisioning40Response(&msg, &provisioning_response); if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || ODK_Message_GetOffset(&msg) != core_message_length) { return ODK_ERROR_CORE_MESSAGE; } /* always verify nonce_values for Renewal and Provisioning responses */ if (!ODK_NonceValuesEqualExcludingVersion( - nonce_values, - &(provisioning_response.request.core_message.nonce_values))) { + nonce_values, &(provisioning_response.core_message.nonce_values))) { return OEMCrypto_ERROR_INVALID_NONCE; } - if (crypto_memcmp(device_id, provisioning_response.request.device_id, - device_id_length) != 0) { - return ODK_ERROR_CORE_MESSAGE; - } - - const uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {0}; - /* check bytes beyond device_id_length are 0 */ - if (crypto_memcmp(zero, - provisioning_response.request.device_id + device_id_length, - ODK_DEVICE_ID_LEN_MAX - device_id_length) != 0) { - return ODK_ERROR_CORE_MESSAGE; - } - return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index b874247..4aa79a4 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -9,6 +9,7 @@ 'target_name': 'odk', 'type': 'static_library', 'standalone_static_library' : 1, + 'hard_dependency': 1, 'include_dirs': [ '../include', '../../include', diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h index 1e9f50d..58a2fd7 100644 --- a/oemcrypto/odk/src/odk_endian.h +++ b/oemcrypto/odk/src/odk_endian.h @@ -25,6 +25,14 @@ extern "C" { #define oemcrypto_be32toh OSSwapBigToHostInt32 #define oemcrypto_htobe64 OSSwapHostToBigInt64 #define oemcrypto_be64toh OSSwapBigToHostInt64 +#elif defined(_WIN32) +#include +#define oemcrypto_htobe16 htons +#define oemcrypto_be16toh ntohs +#define oemcrypto_htobe32 htonl +#define oemcrypto_be32toh ntohl +#define oemcrypto_htobe64 htonll +#define oemcrypto_be64toh ntohll #else /* defined(__linux__) || defined(__ANDROID__) */ uint32_t oemcrypto_htobe16(uint16_t u16); uint32_t oemcrypto_be16toh(uint16_t u16); diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c index 0ebc084..37c3bb9 100644 --- a/oemcrypto/odk/src/odk_overflow.c +++ b/oemcrypto/odk/src/odk_overflow.c @@ -2,6 +2,8 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "odk_overflow.h" + #include #include diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index 5c58200..3d45035 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -6,6 +6,8 @@ * This code is auto-generated, do not edit */ +#include "odk_serialize.h" + #include "odk_structs_priv.h" #include "serialization_base.h" @@ -78,6 +80,48 @@ static void Pack_ODK_ParsedLicense(ODK_Message* msg, Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]); Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]); } + Pack_enum(msg, obj->renewal_delay_base); + Pack_uint32_t(msg, &obj->key_array_length); + size_t i; + for (i = 0; i < (size_t)obj->key_array_length; i++) { + Pack_OEMCrypto_KeyObject(msg, &obj->key_array[i]); + } +} + +static void Pack_ODK_ParsedLicenseV17(ODK_Message* msg, + ODK_ParsedLicenseV17 const* obj) { + /* hand-coded */ + if (obj->key_array_length > ODK_MAX_NUM_KEYS) { + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + return; + } + Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); + Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); + Pack_OEMCrypto_Substring(msg, &obj->pst); + Pack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); + Pack_enum(msg, obj->license_type); + Pack_bool(msg, &obj->nonce_required); + Pack_ODK_TimerLimits(msg, &obj->timer_limits); + Pack_uint32_t(msg, &obj->watermarking); + Pack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required); + if (obj->dtcp2_required.dtcp2_required) { + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]); + } Pack_uint32_t(msg, &obj->key_array_length); size_t i; for (i = 0; i < (size_t)obj->key_array_length; i++) { @@ -114,11 +158,31 @@ static void Pack_ODK_ParsedProvisioning(ODK_Message* msg, Pack_OEMCrypto_Substring(msg, &obj->encrypted_message_key); } +static void Pack_ODK_MessageCounterInfo(ODK_Message* msg, + ODK_MessageCounterInfo const* obj) { + Pack_uint64_t(msg, &obj->master_generation_number); + Pack_uint32_t(msg, &obj->provisioning_count); + Pack_uint32_t(msg, &obj->license_count); + Pack_uint32_t(msg, &obj->decrypt_count); + Pack_uint16_t(msg, &obj->major_version); + Pack_uint16_t(msg, &obj->minor_version); + Pack_uint16_t(msg, &obj->patch_version); + PackArray(msg, &obj->soc_vendor[0], sizeof(obj->soc_vendor)); + PackArray(msg, &obj->chipset_model[0], sizeof(obj->chipset_model)); + PackArray(msg, &obj->extra[0], sizeof(obj->extra)); +} + /* @@ odk serialize */ void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); + Pack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + +void Pack_ODK_PreparedLicenseRequestV17( + ODK_Message* msg, ODK_PreparedLicenseRequestV17 const* obj) { + Pack_ODK_CoreMessage(msg, &obj->core_message); } void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, @@ -130,10 +194,28 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, void Pack_ODK_PreparedProvisioningRequest( ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); + // Fake device_id_length for older servers, since we removed device id from + // the v18 request + uint32_t device_id_len = 64; + Pack_uint32_t(msg, &device_id_len); + Pack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + +void Pack_ODK_PreparedProvisioningRequestV17( + ODK_Message* msg, const ODK_PreparedProvisioningRequestV17* obj) { + Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_uint32_t(msg, &obj->device_id_length); PackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); } +void Pack_ODK_PreparedProvisioning40Request( + ODK_Message* msg, const ODK_PreparedProvisioning40Request* obj) { + Pack_ODK_CoreMessage(msg, &obj->core_message); + Pack_uint32_t(msg, &obj->device_info_length); + PackArray(msg, &obj->device_info[0], sizeof(obj->device_info)); + Pack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + void Pack_ODK_PreparedRenewedProvisioningRequest( ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); @@ -148,13 +230,19 @@ void Pack_ODK_PreparedRenewedProvisioningRequest( void Pack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse const* obj) { - Pack_ODK_PreparedLicenseRequest(msg, &obj->request); + Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license); } +void Pack_ODK_LicenseResponseV17(ODK_Message* msg, + ODK_LicenseResponseV17 const* obj) { + Pack_ODK_PreparedLicenseRequestV17(msg, &obj->request); + Pack_ODK_ParsedLicenseV17(msg, &obj->parsed_license); +} + void Pack_ODK_LicenseResponseV16(ODK_Message* msg, ODK_LicenseResponseV16 const* obj) { - Pack_ODK_PreparedLicenseRequest(msg, &obj->request); + Pack_ODK_PreparedLicenseRequestV17(msg, &obj->request); Pack_ODK_ParsedLicenseV16(msg, &obj->parsed_license); PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } @@ -167,11 +255,23 @@ void Pack_ODK_RenewalResponse(ODK_Message* msg, void Pack_ODK_ProvisioningResponse(ODK_Message* msg, const ODK_ProvisioningResponse* obj) { - Pack_ODK_PreparedProvisioningRequest(msg, &obj->request); + Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_ODK_ParsedProvisioning( msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning); } +void Pack_ODK_ProvisioningResponseV16(ODK_Message* msg, + const ODK_ProvisioningResponseV16* obj) { + Pack_ODK_PreparedProvisioningRequestV17(msg, &obj->request); + Pack_ODK_ParsedProvisioning( + msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning); +} + +void Pack_ODK_Provisioning40Response(ODK_Message* msg, + const ODK_Provisioning40Response* obj) { + Pack_ODK_CoreMessage(msg, &obj->core_message); +} + /* @ deserialize */ /* @@ private deserialize */ @@ -212,7 +312,66 @@ static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) { Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); - obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg); + Unpack_OEMCrypto_LicenseType(msg, &obj->license_type); + Unpack_bool(msg, &obj->nonce_required); + Unpack_ODK_TimerLimits(msg, &obj->timer_limits); + Unpack_uint32_t(msg, &obj->watermarking); + Unpack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required); + if (obj->dtcp2_required.dtcp2_required) { + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]); + } else { + obj->dtcp2_required.dtcp2_required = 0; + obj->dtcp2_required.cmi_descriptor_0.id = 0; + obj->dtcp2_required.cmi_descriptor_0.extension = 0; + obj->dtcp2_required.cmi_descriptor_0.length = 0; + obj->dtcp2_required.cmi_descriptor_0.data = 0; + obj->dtcp2_required.cmi_descriptor_1.id = 0; + obj->dtcp2_required.cmi_descriptor_1.extension = 0; + obj->dtcp2_required.cmi_descriptor_1.length = 0; + obj->dtcp2_required.cmi_descriptor_1.data[0] = 0; + obj->dtcp2_required.cmi_descriptor_1.data[1] = 0; + obj->dtcp2_required.cmi_descriptor_1.data[2] = 0; + obj->dtcp2_required.cmi_descriptor_2.id = 0; + obj->dtcp2_required.cmi_descriptor_2.extension = 0; + obj->dtcp2_required.cmi_descriptor_2.length = 0; + obj->dtcp2_required.cmi_descriptor_2.data[0] = 0; + obj->dtcp2_required.cmi_descriptor_2.data[1] = 0; + obj->dtcp2_required.cmi_descriptor_2.data[2] = 0; + } + Unpack_OEMCrypto_TimerDelayBase(msg, &obj->renewal_delay_base); + Unpack_uint32_t(msg, &obj->key_array_length); + if (obj->key_array_length > ODK_MAX_NUM_KEYS) { + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + return; + } + uint32_t i; + for (i = 0; i < obj->key_array_length; i++) { + Unpack_OEMCrypto_KeyObject(msg, &obj->key_array[i]); + } +} + +static void Unpack_ODK_ParsedLicenseV17(ODK_Message* msg, + ODK_ParsedLicenseV17* obj) { + Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); + Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); + Unpack_OEMCrypto_Substring(msg, &obj->pst); + Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); + Unpack_OEMCrypto_LicenseType(msg, &obj->license_type); Unpack_bool(msg, &obj->nonce_required); Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->watermarking); @@ -270,7 +429,7 @@ static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg, Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); - obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg); + Unpack_OEMCrypto_LicenseType(msg, &obj->license_type); Unpack_bool(msg, &obj->nonce_required); Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->key_array_length); @@ -286,17 +445,37 @@ static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg, static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning* obj) { - obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg); + Unpack_OEMCrypto_PrivateKeyType(msg, &obj->key_type); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key_iv); Unpack_OEMCrypto_Substring(msg, &obj->encrypted_message_key); } +static void Unpack_ODK_MessageCounterInfo(ODK_Message* msg, + ODK_MessageCounterInfo* obj) { + Unpack_uint64_t(msg, &obj->master_generation_number); + Unpack_uint32_t(msg, &obj->provisioning_count); + Unpack_uint32_t(msg, &obj->license_count); + Unpack_uint32_t(msg, &obj->decrypt_count); + Unpack_uint16_t(msg, &obj->major_version); + Unpack_uint16_t(msg, &obj->minor_version); + Unpack_uint16_t(msg, &obj->patch_version); + UnpackArray(msg, &obj->soc_vendor[0], sizeof(obj->soc_vendor)); + UnpackArray(msg, &obj->chipset_model[0], sizeof(obj->chipset_model)); + UnpackArray(msg, &obj->extra[0], sizeof(obj->extra)); +} + /* @ kdo deserialize */ void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); + Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + +void Unpack_ODK_PreparedLicenseRequestV17(ODK_Message* msg, + ODK_PreparedLicenseRequestV17* obj) { + Unpack_ODK_CoreMessage(msg, &obj->core_message); } void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, @@ -308,10 +487,28 @@ void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, void Unpack_ODK_PreparedProvisioningRequest( ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); + // Fake device_id_length for older servers, since we removed device id from + // the v18 request + uint32_t device_id_len = 0; + Unpack_uint32_t(msg, &device_id_len); + Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + +void Unpack_ODK_PreparedProvisioningRequestV17( + ODK_Message* msg, ODK_PreparedProvisioningRequestV17* obj) { + Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_uint32_t(msg, &obj->device_id_length); UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); } +void Unpack_ODK_PreparedProvisioning40Request( + ODK_Message* msg, ODK_PreparedProvisioning40Request* obj) { + Unpack_ODK_CoreMessage(msg, &obj->core_message); + Unpack_uint32_t(msg, &obj->device_info_length); + UnpackArray(msg, &obj->device_info[0], sizeof(obj->device_info)); + Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info); +} + void Unpack_ODK_PreparedRenewedProvisioningRequest( ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); @@ -329,13 +526,19 @@ void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, /* @@ odk deserialize */ void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) { - Unpack_ODK_PreparedLicenseRequest(msg, &obj->request); + Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_ODK_ParsedLicense(msg, obj->parsed_license); } +void Unpack_ODK_LicenseResponseV17(ODK_Message* msg, + ODK_LicenseResponseV17* obj) { + Unpack_ODK_PreparedLicenseRequestV17(msg, &obj->request); + Unpack_ODK_ParsedLicenseV17(msg, &obj->parsed_license); +} + void Unpack_ODK_LicenseResponseV16(ODK_Message* msg, ODK_LicenseResponseV16* obj) { - Unpack_ODK_PreparedLicenseRequest(msg, &obj->request); + Unpack_ODK_PreparedLicenseRequestV17(msg, &obj->request); Unpack_ODK_ParsedLicenseV16(msg, &obj->parsed_license); UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } @@ -347,6 +550,17 @@ void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) { void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj) { - Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request); + Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning); } + +void Unpack_ODK_ProvisioningResponseV16(ODK_Message* msg, + ODK_ProvisioningResponseV16* obj) { + Unpack_ODK_PreparedProvisioningRequestV17(msg, &obj->request); + Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning); +} + +void Unpack_ODK_Provisioning40Response(ODK_Message* msg, + ODK_Provisioning40Response* obj) { + Unpack_ODK_CoreMessage(msg, &obj->core_message); +} diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h index 0904700..db9e2f6 100644 --- a/oemcrypto/odk/src/odk_serialize.h +++ b/oemcrypto/odk/src/odk_serialize.h @@ -8,8 +8,8 @@ #ifndef WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_ #define WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_ +#include "odk_message.h" #include "odk_structs_priv.h" -#include "serialization_base.h" #ifdef __cplusplus extern "C" { @@ -18,37 +18,61 @@ extern "C" { /* odk pack */ void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, const ODK_PreparedLicenseRequest* obj); +void Pack_ODK_PreparedLicenseRequestV17( + ODK_Message* msg, const ODK_PreparedLicenseRequestV17* obj); void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, const ODK_PreparedRenewalRequest* obj); void Pack_ODK_PreparedProvisioningRequest( ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj); +void Pack_ODK_PreparedProvisioningRequestV17( + ODK_Message* msg, const ODK_PreparedProvisioningRequestV17* obj); +void Pack_ODK_PreparedProvisioning40Request( + ODK_Message* msg, const ODK_PreparedProvisioning40Request* obj); void Pack_ODK_PreparedRenewedProvisioningRequest( ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj); /* odk unpack */ void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj); void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj); +void Unpack_ODK_LicenseResponseV17(ODK_Message* msg, + ODK_LicenseResponseV17* obj); void Unpack_ODK_LicenseResponseV16(ODK_Message* msg, ODK_LicenseResponseV16* obj); void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj); void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj); +void Unpack_ODK_ProvisioningResponseV16(ODK_Message* msg, + ODK_ProvisioningResponseV16* obj); +void Unpack_ODK_Provisioning40Response(ODK_Message* msg, + ODK_Provisioning40Response* obj); /* kdo pack */ void Pack_ODK_LicenseResponse(ODK_Message* msg, const ODK_LicenseResponse* obj); +void Pack_ODK_LicenseResponseV17(ODK_Message* msg, + const ODK_LicenseResponseV17* obj); void Pack_ODK_LicenseResponseV16(ODK_Message* msg, const ODK_LicenseResponseV16* obj); void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj); void Pack_ODK_ProvisioningResponse(ODK_Message* msg, const ODK_ProvisioningResponse* obj); +void Pack_ODK_ProvisioningResponseV16(ODK_Message* msg, + const ODK_ProvisioningResponseV16* obj); +void Pack_ODK_Provisioning40Response(ODK_Message* msg, + const ODK_Provisioning40Response* obj); /* kdo unpack */ void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj); +void Unpack_ODK_PreparedLicenseRequestV17(ODK_Message* msg, + ODK_PreparedLicenseRequestV17* obj); void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj); void Unpack_ODK_PreparedProvisioningRequest( ODK_Message* msg, ODK_PreparedProvisioningRequest* obj); +void Unpack_ODK_PreparedProvisioningRequestV17( + ODK_Message* msg, ODK_PreparedProvisioningRequestV17* obj); +void Unpack_ODK_PreparedProvisioning40Request( + ODK_Message* msg, ODK_PreparedProvisioning40Request* obj); void Unpack_ODK_PreparedRenewedProvisioningRequest( ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj); diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h index 3fe73ee..b20cc72 100644 --- a/oemcrypto/odk/src/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -25,8 +25,10 @@ typedef uint32_t ODK_MessageType; #define ODK_Provisioning_Request_Type ((ODK_MessageType)5u) #define ODK_Provisioning_Response_Type ((ODK_MessageType)6u) #define ODK_Renewed_Provisioning_Request_Type ((ODK_MessageType)11u) +#define ODK_Provisioning40_Request_Type ((ODK_MessageType)12u) -// Reserve future message types to support forward compatibility. +// TODO(b/244580447): Reserve future message types to support +// forward compatibility. #define ODK_Release_Request_Type ((ODK_MessageType)7u) #define ODK_Release_Response_Type ((ODK_MessageType)8u) #define ODK_Common_Request_Type ((ODK_MessageType)9u) @@ -40,18 +42,35 @@ typedef struct { typedef struct { ODK_CoreMessage core_message; + ODK_MessageCounterInfo counter_info; } ODK_PreparedLicenseRequest; +typedef struct { + ODK_CoreMessage core_message; +} ODK_PreparedLicenseRequestV17; + typedef struct { ODK_CoreMessage core_message; uint64_t playback_time; } ODK_PreparedRenewalRequest; +typedef struct { + ODK_CoreMessage core_message; + ODK_MessageCounterInfo counter_info; +} ODK_PreparedProvisioningRequest; + typedef struct { ODK_CoreMessage core_message; uint32_t device_id_length; uint8_t device_id[ODK_DEVICE_ID_LEN_MAX]; -} ODK_PreparedProvisioningRequest; +} ODK_PreparedProvisioningRequestV17; + +typedef struct { + ODK_CoreMessage core_message; + uint32_t device_info_length; + uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX]; + ODK_MessageCounterInfo counter_info; +} ODK_PreparedProvisioning40Request; typedef struct { ODK_CoreMessage core_message; @@ -79,12 +98,32 @@ typedef struct { } ODK_ParsedLicenseV16; typedef struct { - ODK_PreparedLicenseRequest request; + OEMCrypto_Substring enc_mac_keys_iv; + OEMCrypto_Substring enc_mac_keys; + OEMCrypto_Substring pst; + OEMCrypto_Substring srm_restriction_data; + OEMCrypto_LicenseType license_type; + bool nonce_required; + ODK_TimerLimits timer_limits; + uint32_t watermarking; + OEMCrypto_DTCP2_CMI_Packet dtcp2_required; + uint32_t key_array_length; + OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS]; +} ODK_ParsedLicenseV17; + +typedef struct { + ODK_CoreMessage core_message; ODK_ParsedLicense* parsed_license; } ODK_LicenseResponse; typedef struct { - ODK_PreparedLicenseRequest request; + ODK_PreparedLicenseRequestV17 request; + ODK_ParsedLicenseV17 parsed_license; + uint8_t request_hash[ODK_SHA256_HASH_SIZE]; +} ODK_LicenseResponseV17; + +typedef struct { + ODK_PreparedLicenseRequestV17 request; ODK_ParsedLicenseV16 parsed_license; uint8_t request_hash[ODK_SHA256_HASH_SIZE]; } ODK_LicenseResponseV16; @@ -95,18 +134,31 @@ typedef struct { } ODK_RenewalResponse; typedef struct { - ODK_PreparedProvisioningRequest request; + ODK_CoreMessage core_message; ODK_ParsedProvisioning* parsed_provisioning; } ODK_ProvisioningResponse; +// Used by V16 and V17 +typedef struct { + ODK_PreparedProvisioningRequestV17 request; + ODK_ParsedProvisioning* parsed_provisioning; +} ODK_ProvisioningResponseV16; + +typedef struct { + ODK_CoreMessage core_message; +} ODK_Provisioning40Response; + // These are the sum of sizeof of each individual member of the request structs // without any padding added by the compiler. Make sure they get updated when // request structs change. Refer to test suite OdkSizeTest in // ../test/odk_test.cpp for validations of each of the defined request sizes. -#define ODK_LICENSE_REQUEST_SIZE 20u +#define ODK_CORE_MESSAGE_SIZE 20u +#define ODK_LICENSE_REQUEST_SIZE 90u #define ODK_RENEWAL_REQUEST_SIZE 28u -#define ODK_PROVISIONING_REQUEST_SIZE 88u +#define ODK_PROVISIONING_REQUEST_SIZE 94u +#define ODK_PROVISIONING40_REQUEST_SIZE 862u #define ODK_RENEWED_PROVISIONING_REQUEST_SIZE 1694u +#define ODK_MESSAGECOUNTERINFO_SIZE 70u // These are the possible timer status values. #define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen. diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 30af34c..b84385b 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -108,10 +108,40 @@ static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) { } } -int Unpack_enum(ODK_Message* message) { - uint32_t v32; +void Unpack_OEMCrypto_LicenseType(ODK_Message* message, + OEMCrypto_LicenseType* value) { + assert(value); + uint32_t v32 = 0; Unpack_uint32_t(message, &v32); - return (int)v32; + if (v32 <= OEMCrypto_LicenseType_MaxValue) { + *value = (OEMCrypto_LicenseType)v32; + } else { + ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); + } +} + +void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message, + OEMCrypto_PrivateKeyType* value) { + assert(value); + uint32_t v32 = 0; + Unpack_uint32_t(message, &v32); + if (v32 <= OEMCrypto_PrivateKeyType_MaxValue) { + *value = (OEMCrypto_PrivateKeyType)v32; + } else { + ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); + } +} + +void Unpack_OEMCrypto_TimerDelayBase(ODK_Message* message, + OEMCrypto_TimerDelayBase* value) { + assert(value); + uint32_t v32 = 0; + Unpack_uint32_t(message, &v32); + if (v32 <= OEMCrypto_TimerDelayBase_MaxValue) { + *value = (OEMCrypto_TimerDelayBase)v32; + } else { + ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); + } } void Unpack_bool(ODK_Message* message, bool* value) { diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index 7b69e11..299e047 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -25,7 +25,12 @@ void PackArray(ODK_Message* message, const uint8_t* base, size_t size); void Pack_OEMCrypto_Substring(ODK_Message* message, const OEMCrypto_Substring* obj); -int Unpack_enum(ODK_Message* message); +void Unpack_OEMCrypto_LicenseType(ODK_Message* message, + OEMCrypto_LicenseType* value); +void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message, + OEMCrypto_PrivateKeyType* value); +void Unpack_OEMCrypto_TimerDelayBase(ODK_Message* message, + OEMCrypto_TimerDelayBase* value); void Unpack_bool(ODK_Message* message, bool* value); void Unpack_uint8_t(ODK_Message* message, uint8_t* value); void Unpack_uint16_t(ODK_Message* message, uint16_t* value); diff --git a/oemcrypto/odk/test/fuzzing/Android.bp b/oemcrypto/odk/test/fuzzing/Android.bp index 3b8fe6d..f351217 100644 --- a/oemcrypto/odk/test/fuzzing/Android.bp +++ b/oemcrypto/odk/test/fuzzing/Android.bp @@ -11,6 +11,7 @@ package { // all of the 'license_kinds' from "vendor_widevine_license" // to get the below license kinds: // legacy_by_exception_only (by exception only) + // legacy_proprietary (by exception only) default_applicable_licenses: ["vendor_widevine_license"], } diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp index 78519cb..0a0c0ae 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp @@ -18,6 +18,7 @@ package { // all of the 'license_kinds' from "vendor_widevine_license" // to get the below license kinds: // legacy_by_exception_only (by exception only) + // legacy_proprietary (by exception only) default_applicable_licenses: ["vendor_widevine_license"], } diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c index 0a2d074..655bd06 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c @@ -113,15 +113,14 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, OEMCryptoResult ODK_PrepareCoreProvisioningRequest( uint8_t* message, size_t message_length, size_t* core_message_length, - const ODK_NonceValues* nonce_values, const uint8_t* device_id, - size_t device_id_length) { + const ODK_NonceValues* nonce_values, + const ODK_MessageCounterInfo* counter_info) { OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*, - const ODK_NonceValues*, const uint8_t*, - size_t); + const ODK_NonceValues*, + const ODK_MessageCounterInfo*); original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreProvisioningRequest"); - OEMCryptoResult oem_crypto_result = - (*original_function)(message, message_length, core_message_length, - nonce_values, device_id, device_id_length); + OEMCryptoResult oem_crypto_result = (*original_function)( + message, message_length, core_message_length, nonce_values, counter_info); char* file_name = GetFileName("provisioning_request_corpus"); // Provisioning Request format expected by fuzzer - [Core Provisioning @@ -134,18 +133,19 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( OEMCryptoResult ODK_ParseProvisioning( const uint8_t* message, size_t message_length, size_t core_message_length, const ODK_NonceValues* nonce_values, const uint8_t* device_id, - size_t device_id_length, ODK_ParsedProvisioning* parsed_response) { + size_t device_id_length, ODK_MessageCounterInfo* counter_info, + ODK_ParsedProvisioning* parsed_response) { struct ODK_ParseProvisioning_Args parse_provisioning_args; parse_provisioning_args.nonce_values = *nonce_values; memcpy(parse_provisioning_args.device_id, device_id, device_id_length); parse_provisioning_args.device_id_length = device_id_length; - OEMCryptoResult (*original_function)(const uint8_t*, size_t, size_t, - const ODK_NonceValues*, const uint8_t*, - size_t, ODK_ParsedProvisioning*); + OEMCryptoResult (*original_function)( + const uint8_t*, size_t, size_t, const ODK_NonceValues*, const uint8_t*, + size_t, ODK_MessageCounterInfo*, ODK_ParsedProvisioning*); original_function = dlsym(RTLD_NEXT, "ODK_ParseProvisioning"); OEMCryptoResult oem_crypto_result = (*original_function)( message, message_length, core_message_length, nonce_values, device_id, - device_id_length, parsed_response); + device_id_length, counter_info, parsed_response); char* file_name = GetFileName("provisioning_response_corpus"); // Provisioning Response format expected by fuzzer - diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp index 1f3b230..ad20cb7 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp @@ -6,6 +6,7 @@ #include #include "odk.h" +#include "odk_structs.h" namespace oemcrypto_core_message { using features::CoreMessageFeatures; @@ -39,7 +40,10 @@ OEMCryptoResult odk_serialize_LicenseRequest( const void* in UNUSED, uint8_t* out, size_t* size, const ODK_LicenseRequest& core_license_request UNUSED, const ODK_NonceValues* nonce_values) { - return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values); + // TODO(mattfedd): hook up counters to fuzzer + const ODK_MessageCounterInfo counter_info = {0}; + return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values, + &counter_info); } OEMCryptoResult odk_serialize_RenewalRequest( @@ -56,10 +60,10 @@ OEMCryptoResult odk_serialize_ProvisioningRequest( const void* in UNUSED, uint8_t* out, size_t* size, const ODK_ProvisioningRequest& core_provisioning, const ODK_NonceValues* nonce_values) { - const std::string& device_id = core_provisioning.device_id; - return ODK_PrepareCoreProvisioningRequest( - out, SIZE_MAX, size, nonce_values, - reinterpret_cast(device_id.data()), device_id.size()); + // TODO(mattfedd): hook up counters to fuzzer + const ODK_MessageCounterInfo counter_info = {0}; + return ODK_PrepareCoreProvisioningRequest(out, SIZE_MAX, size, nonce_values, + &counter_info); } OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, @@ -69,9 +73,9 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, ODK_ParsedLicense* parsed_lic) { return ODK_ParseLicense(message, SIZE_MAX, core_message_length, static_cast(a->initial_license_load), - static_cast(a->usage_entry_present), + static_cast(a->usage_entry_present), 0, &a->timer_limits, &a->clock_values, nonce_values, - parsed_lic); + parsed_lic, nullptr); } OEMCryptoResult odk_deserialize_RenewalResponse( diff --git a/oemcrypto/odk/test/odk_core_message_test.cpp b/oemcrypto/odk/test/odk_core_message_test.cpp index 22051b2..2ed15d4 100644 --- a/oemcrypto/odk/test/odk_core_message_test.cpp +++ b/oemcrypto/odk/test/odk_core_message_test.cpp @@ -3,13 +3,22 @@ // License Agreement. #include +#include #include "OEMCryptoCENCCommon.h" +#include "core_message_deserialize.h" +#include "core_message_types.h" #include "gtest/gtest.h" #include "odk.h" #include "third_party/absl/strings/escaping.h" namespace wvodk_test { + +using oemcrypto_core_message::ODK_CommonRequest; +using oemcrypto_core_message::ODK_ProvisioningRequest; +using oemcrypto_core_message::deserialize::CoreCommonRequestFromMessage; +using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; + TEST(CoreMessageTest, RenwalRequest) { std::string oem = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst" @@ -36,4 +45,64 @@ TEST(CoreMessageTest, RenwalRequest) { char* m = reinterpret_cast(message); VLOG(0) << absl::BytesToHexString(std::string(m, core_message_length)); } + +TEST(CoreMessageTest, ParseCoreCommonRequestFromMessage) { + // Core message header format: + // message_type : 4 bytes + // message_length : 4 bytes + // minor_version : 2 bytes + // major_version : 2 bytes + // nonce : 4 bytes + // session_id : 4 bytes + const char kv16CoreMessageLicenseRequest[] = + "0000000100000014000300100000000100000001"; + std::string oemcrypto_core_message = + absl::HexStringToBytes(kv16CoreMessageLicenseRequest); + ODK_CommonRequest odk_common_request; + ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message, + &odk_common_request)); + EXPECT_EQ(odk_common_request.message_type, 1); + EXPECT_EQ(odk_common_request.message_length, 20); + EXPECT_EQ(odk_common_request.api_minor_version, 3); + EXPECT_EQ(odk_common_request.api_major_version, 16); + EXPECT_EQ(odk_common_request.nonce, 1); + EXPECT_EQ(odk_common_request.session_id, 1); +} + +// Make sure that the first version of the V18 provisioning request (no hidden +// 4-byte value, all 0s in message counter struct) will still parse with current +// v18 code. +TEST(CoreMessageTest, ProvisionRequestRoundtrip_V18_Initial) { + std::vector should_pass = { + // Pulled from ODKTest provision round trip, extra 4 bytes removed + "000000050000005e00000012deadbeefcafebabe000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000", + // Same thing but v17 in nonce. Almost like testing on the v17 server (but + // not quite since the v17 parsing code has been slightly changed anyway) + "000000050000005e00000011deadbeefcafebabe000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000", + }; + + ODK_ProvisioningRequest request; + for (auto& tc : should_pass) { + ASSERT_TRUE(CoreProvisioningRequestFromMessage(absl::HexStringToBytes(tc), + &request)); + } + + // Fail cases have non-zero values after the bytes interpreted as length + std::vector should_fail = { + // Change a 0 to a 1 in the message counter + "000000050000005e00000012deadbeefcafebabe000000000000000100000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000", + }; + + for (auto& tc : should_fail) { + ASSERT_FALSE(CoreProvisioningRequestFromMessage(absl::HexStringToBytes(tc), + &request)); + } +} + } // namespace wvodk_test diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index a244d25..6cd9319 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -6,14 +6,18 @@ #include #include +#include #include +#include #include "OEMCryptoCENCCommon.h" #include "core_message_deserialize.h" #include "core_message_features.h" #include "core_message_serialize.h" +#include "core_message_serialize_proto.h" #include "core_message_types.h" #include "gtest/gtest.h" +#include "odk_structs.h" #include "odk_structs_priv.h" #include "odk_test_helper.h" @@ -21,11 +25,16 @@ namespace wvodk_test { namespace { +using oemcrypto_core_message::ODK_CommonRequest; using oemcrypto_core_message::ODK_LicenseRequest; +using oemcrypto_core_message::ODK_MessageCounter; +using oemcrypto_core_message::ODK_Provisioning40Request; using oemcrypto_core_message::ODK_ProvisioningRequest; using oemcrypto_core_message::ODK_RenewalRequest; +using oemcrypto_core_message::deserialize::CoreCommonRequestFromMessage; using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; +using oemcrypto_core_message::deserialize::CoreProvisioning40RequestFromMessage; using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; using oemcrypto_core_message::deserialize:: @@ -34,7 +43,10 @@ using oemcrypto_core_message::deserialize:: using oemcrypto_core_message::features::CoreMessageFeatures; using oemcrypto_core_message::serialize::CreateCoreLicenseResponse; +using oemcrypto_core_message::serialize::CreateCoreProvisioning40Response; using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; +using oemcrypto_core_message::serialize:: + CreateCoreProvisioningResponseFromProto; using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; constexpr uint32_t kExtraPayloadSize = 128u; @@ -59,6 +71,40 @@ void PrintTo(const VersionParameters& p, std::ostream* os) { << p.response_minor_version; } +void SetDefaultSerializedProvisioningResponse(std::string* serialized_message) { + // Create a dummy provisioning response + video_widevine::ProvisioningResponse provisioning_response; + provisioning_response.set_device_certificate("device_certificate"); + provisioning_response.set_device_rsa_key("device_rsa_key"); + provisioning_response.set_device_rsa_key_iv("device_rsa_key_iv"); + if (!provisioning_response.SerializeToString(serialized_message)) { + FAIL(); + } +} + +bool CheckCounterInfoIsEqual(ODK_MessageCounterInfo* a, ODK_MessageCounter* b) { + if (!a || !b) return false; + + EXPECT_EQ(a->master_generation_number, b->master_generation_number); + EXPECT_EQ(a->provisioning_count, b->provisioning_count); + EXPECT_EQ(a->license_count, b->license_count); + EXPECT_EQ(a->decrypt_count, b->decrypt_count); + EXPECT_EQ(a->major_version, b->major_version); + EXPECT_EQ(a->minor_version, b->minor_version); + EXPECT_EQ(a->patch_version, b->patch_version); + for (size_t i = 0; i < sizeof(a->soc_vendor); i++) { + EXPECT_EQ(a->soc_vendor[i], b->soc_vendor[i]); + } + for (size_t i = 0; i < sizeof(a->chipset_model); i++) { + EXPECT_EQ(a->chipset_model[i], b->chipset_model[i]); + } + for (size_t i = 0; i < sizeof(a->extra); i++) { + EXPECT_EQ(a->extra[i], b->extra[i]); + } + + return true; +} + template void ValidateRequest(uint32_t message_type, const std::vector& extra_fields, @@ -241,13 +287,19 @@ TEST(OdkTest, NullRequestTest) { memset(&nonce_values, 0, sizeof(nonce_values)); ODK_ClockValues clock_values; memset(&clock_values, 0, sizeof(clock_values)); + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); // Assert that nullptr does not cause a core dump. - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest( - nullptr, 0uL, nullptr, &nonce_values)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreLicenseRequest(nullptr, 0uL, nullptr, &nonce_values, + &counter_info)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length, - nullptr)); + nullptr, &counter_info)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length, + &nonce_values, nullptr)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewalRequest(nullptr, 0uL, nullptr, &nonce_values, @@ -261,10 +313,23 @@ TEST(OdkTest, NullRequestTest) { EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioningRequest( - nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL)); + nullptr, 0uL, &core_message_length, nullptr, &counter_info)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioningRequest(nullptr, 0uL, nullptr, - &nonce_values, nullptr, 0uL)); + &nonce_values, &counter_info)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreProvisioningRequest( + nullptr, 0uL, &core_message_length, &nonce_values, nullptr)); + + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request( + nullptr, 0uL, &core_message_length, + nullptr, nullptr, 0uL, &counter_info)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request( + nullptr, 0uL, nullptr, &nonce_values, + nullptr, 0uL, &counter_info)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request( + nullptr, 0uL, &core_message_length, + &nonce_values, nullptr, 0uL, nullptr)); // Null device id in provisioning request is ok uint8_t message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; @@ -272,7 +337,16 @@ TEST(OdkTest, NullRequestTest) { EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreProvisioningRequest( message, ODK_PROVISIONING_REQUEST_SIZE, &core_message_length, - &nonce_values, nullptr, 0uL)); + &nonce_values, &counter_info)); + + // Null device info in provisioning 4.0 request is ok + uint8_t message_prov4[ODK_PROVISIONING40_REQUEST_SIZE] = {0}; + core_message_length = ODK_PROVISIONING40_REQUEST_SIZE; + EXPECT_EQ( + OEMCrypto_SUCCESS, + ODK_PrepareCoreProvisioning40Request( + message_prov4, ODK_PROVISIONING40_REQUEST_SIZE, &core_message_length, + &nonce_values, nullptr, 0uL, &counter_info)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewedProvisioningRequest( @@ -316,26 +390,26 @@ TEST(OdkTest, NullResponseTest) { memset(&clock_values, 0, sizeof(clock_values)); // Assert that nullptr does not cause a core dump. - EXPECT_EQ( - ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, true, - &timer_limits, &clock_values, &nonce_values, nullptr)); - EXPECT_EQ( - ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, true, - &timer_limits, &clock_values, nullptr, &parsed_license)); - EXPECT_EQ( - ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, true, - &timer_limits, nullptr, &nonce_values, &parsed_license)); - EXPECT_EQ( - ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, true, - nullptr, &clock_values, &nonce_values, &parsed_license)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, + true, 0, &timer_limits, &clock_values, + &nonce_values, nullptr, nullptr)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, + true, 0, &timer_limits, &clock_values, nullptr, + &parsed_license, nullptr)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, + true, 0, &timer_limits, nullptr, &nonce_values, + &parsed_license, nullptr)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, + true, 0, nullptr, &clock_values, &nonce_values, + &parsed_license, nullptr)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(nullptr, message_size, core_message_length, true, - true, &timer_limits, &clock_values, &nonce_values, - &parsed_license)); + true, 0, &timer_limits, &clock_values, + &nonce_values, &parsed_license, nullptr)); constexpr uint64_t system_time = 0; uint64_t timer_value = 0; @@ -373,6 +447,13 @@ TEST(OdkTest, NullResponseTest) { ODK_ParseProvisioning(nullptr, message_size, core_message_length, &nonce_values, device_id, ODK_DEVICE_ID_LEN_MAX, &parsed_response)); + + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseProvisioning40(message, message_size, core_message_length, + nullptr)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_ParseProvisioning40(nullptr, message_size, core_message_length, + &nonce_values)); } TEST(OdkTest, PrepareCoreLicenseRequest) { @@ -380,9 +461,12 @@ TEST(OdkTest, PrepareCoreLicenseRequest) { size_t core_message_length = sizeof(license_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); - EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest( - license_message, sizeof(license_message), - &core_message_length, &nonce_values)); + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); + EXPECT_EQ(OEMCrypto_SUCCESS, + ODK_PrepareCoreLicenseRequest( + license_message, sizeof(license_message), &core_message_length, + &nonce_values, &counter_info)); } TEST(OdkTest, PrepareCoreLicenseRequestSize) { @@ -390,18 +474,20 @@ TEST(OdkTest, PrepareCoreLicenseRequestSize) { size_t core_message_length = sizeof(license_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); // message length smaller than core message length size_t core_message_length_invalid = core_message_length + 1; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest( license_message, sizeof(license_message), - &core_message_length_invalid, &nonce_values)); + &core_message_length_invalid, &nonce_values, &counter_info)); // message length larger than core message length uint8_t license_message_large[ODK_LICENSE_REQUEST_SIZE * 2] = {0}; EXPECT_EQ(OEMCrypto_SUCCESS, - ODK_PrepareCoreLicenseRequest(license_message_large, - sizeof(license_message_large), - &core_message_length, &nonce_values)); + ODK_PrepareCoreLicenseRequest( + license_message_large, sizeof(license_message_large), + &core_message_length, &nonce_values, &counter_info)); } TEST(OdkTest, PrepareCoreRenewalRequest) { @@ -446,12 +532,27 @@ TEST(OdkTest, PrepareCoreProvisioningRequest) { size_t core_message_length = sizeof(provisioning_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); - uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; - EXPECT_EQ( - OEMCrypto_SUCCESS, - ODK_PrepareCoreProvisioningRequest( - provisioning_message, sizeof(provisioning_message), - &core_message_length, &nonce_values, device_id, sizeof(device_id))); + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); + EXPECT_EQ(OEMCrypto_SUCCESS, + ODK_PrepareCoreProvisioningRequest( + provisioning_message, sizeof(provisioning_message), + &core_message_length, &nonce_values, &counter_info)); +} + +TEST(OdkTest, PrepareCoreProvisioning40Request) { + uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0}; + size_t core_message_length = sizeof(provisioning_message); + ODK_NonceValues nonce_values; + memset(&nonce_values, 0, sizeof(nonce_values)); + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); + uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0}; + EXPECT_EQ(OEMCrypto_SUCCESS, + ODK_PrepareCoreProvisioning40Request( + provisioning_message, sizeof(provisioning_message), + &core_message_length, &nonce_values, device_info, + sizeof(device_info), &counter_info)); } TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) { @@ -469,17 +570,19 @@ TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) { OEMCrypto_RenewalACert, renewal_data, sizeof(renewal_data))); } -TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) { - uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; +TEST(OdkTest, PrepareCoreProvisioning40RequestDeviceInfo) { + uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(provisioning_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); - uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0}; + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); + uint8_t device_info_invalid[ODK_DEVICE_INFO_LEN_MAX + 1] = {0}; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_PrepareCoreProvisioningRequest( + ODK_PrepareCoreProvisioning40Request( provisioning_message, sizeof(provisioning_message), - &core_message_length, &nonce_values, device_id_invalid, - sizeof(device_id_invalid))); + &core_message_length, &nonce_values, device_info_invalid, + sizeof(device_info_invalid), &counter_info)); } TEST(OdkTest, PrepareCoreRenewedProvisioningRequestDeviceId) { @@ -514,13 +617,36 @@ TEST(OdkTest, PrepareCoreRenewedProvisioningRequestRenewalDataInvalid) { // Serialize and de-serialize license request TEST(OdkTest, LicenseRequestRoundtrip) { - std::vector empty; + ODK_MessageCounterInfo counter_info; + counter_info.master_generation_number = 0x12345678abcdffff; + counter_info.provisioning_count = 12; + counter_info.license_count = 50; + counter_info.decrypt_count = 340; + counter_info.major_version = ODK_MAJOR_VERSION; + counter_info.minor_version = ODK_MINOR_VERSION; + counter_info.patch_version = 4; + memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor)); + memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model)); + memset(counter_info.extra, 0xee, sizeof(counter_info.extra)); + std::vector extra_fields = { + {ODK_MESSAGECOUNTER, &counter_info, "counter_info"}, + }; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, ODK_NonceValues* nonce_values) { - return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values); + return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values, + &counter_info); }; - auto kdo_parse_func = CoreLicenseRequestFromMessage; - ValidateRequest(ODK_License_Request_Type, empty, + auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, + ODK_LicenseRequest* core_license_request) { + bool ok = CoreLicenseRequestFromMessage(oemcrypto_core_message, + core_license_request); + if (!ok) return false; + + ok = CheckCounterInfoIsEqual(&counter_info, + &core_license_request->counter_info); + return ok; + }; + ValidateRequest(ODK_License_Request_Type, extra_fields, odk_prepare_func, kdo_parse_func); } @@ -550,23 +676,38 @@ TEST(OdkTest, RenewalRequestRoundtrip) { } TEST(OdkTest, ProvisionRequestRoundtrip) { - uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; - uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; - memset(device_id, 0xff, device_id_length); + ODK_MessageCounterInfo counter_info; + counter_info.master_generation_number = 0x12345678abcdffff; + counter_info.provisioning_count = 12; + counter_info.license_count = 50; + counter_info.decrypt_count = 340; + counter_info.major_version = ODK_MAJOR_VERSION; + counter_info.minor_version = ODK_MINOR_VERSION; + counter_info.patch_version = 4; + memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor)); + memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model)); + memset(counter_info.extra, 0xee, sizeof(counter_info.extra)); + // Fake device_id_length for older servers, since we removed device id from + // the v18 request + uint32_t fake_device_id_length = 64; std::vector extra_fields = { - {ODK_UINT32, &device_id_length, "device_id_length"}, - {ODK_DEVICEID, device_id, "device_id"}, + {ODK_UINT32, &(fake_device_id_length), "fake_device_id_length"}, + {ODK_MESSAGECOUNTER, &counter_info, "counter_info"}, }; + auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, const ODK_NonceValues* nonce_values) { return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values, - device_id, device_id_length); + &counter_info); }; auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request) { bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message, core_provisioning_request); + if (!ok) return false; + ok = CheckCounterInfoIsEqual(&counter_info, + &core_provisioning_request->counter_info); return ok; }; ValidateRequest(ODK_Provisioning_Request_Type, @@ -574,6 +715,47 @@ TEST(OdkTest, ProvisionRequestRoundtrip) { kdo_parse_func); } +TEST(OdkTest, ProvisionRequest40Roundtrip) { + uint32_t device_info_length = ODK_DEVICE_INFO_LEN_MAX / 2; + uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0}; + memset(device_info, 0xaa, device_info_length); + ODK_MessageCounterInfo counter_info; + counter_info.master_generation_number = 0x12345678abcdffff; + counter_info.provisioning_count = 12; + counter_info.license_count = 50; + counter_info.decrypt_count = 340; + counter_info.major_version = ODK_MAJOR_VERSION; + counter_info.minor_version = ODK_MINOR_VERSION; + counter_info.patch_version = 4; + memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor)); + memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model)); + memset(counter_info.extra, 0xee, sizeof(counter_info.extra)); + std::vector extra_fields = { + {ODK_UINT32, &device_info_length, "device_info_length"}, + {ODK_DEVICEINFO, device_info, "device_info"}, + {ODK_MESSAGECOUNTER, &counter_info, "counter_info"}, + }; + auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, + const ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreProvisioning40Request( + buf, SIZE_MAX, size, nonce_values, device_info, device_info_length, + &counter_info); + }; + auto kdo_parse_func = + [&](const std::string& oemcrypto_core_message, + ODK_Provisioning40Request* core_provisioning_request) { + bool ok = CoreProvisioning40RequestFromMessage( + oemcrypto_core_message, core_provisioning_request); + if (!ok) return false; + ok = CheckCounterInfoIsEqual(&counter_info, + &core_provisioning_request->counter_info); + return ok; + }; + ValidateRequest(ODK_Provisioning40_Request_Type, + extra_fields, odk_prepare_func, + kdo_parse_func); +} + TEST(OdkTest, RenewedProvisionRequestRoundtrip) { uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; @@ -618,9 +800,9 @@ TEST(OdkTest, ParseLicenseErrorNonce) { params.core_message.nonce_values.nonce = 0; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err); delete[] buf; } @@ -635,9 +817,9 @@ TEST(OdkTest, ParseLicenseErrorUsageEntry) { params.usage_entry_present = false; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } @@ -653,9 +835,9 @@ TEST(OdkTest, ParseLicenseNullSubstring) { &buf_size); OEMCryptoResult result = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); EXPECT_EQ(OEMCrypto_SUCCESS, result); delete[] buf; } @@ -671,9 +853,9 @@ TEST(OdkTest, ParseLicenseErrorSubstringOffset) { &buf_size); OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; @@ -687,9 +869,9 @@ TEST(OdkTest, ParseLicenseErrorSubstringOffset) { &buf_size); err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } @@ -710,20 +892,50 @@ TEST(OdkTest, ParseRenewalErrorTimer) { delete[] buf; } -TEST(OdkTest, ParsePrivisioningErrorDeviceId) { - ODK_ProvisioningResponseParams params; - ODK_SetDefaultProvisioningResponseParams(¶ms); - uint8_t* buf = nullptr; - uint32_t buf_size = 0; - ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, - &buf_size); - // temporarily mess up with device_id - params.device_id[0] = 0; - OEMCryptoResult err = ODK_ParseProvisioning( - buf, buf_size + 16, buf_size, &(params.core_message.nonce_values), - params.device_id, params.device_id_length, &(params.parsed_provisioning)); - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); - delete[] buf; +TEST(OdkTest, ProvisionResponseFromProto) { + std::string serialized_provisioning_resp; + EXPECT_NO_FATAL_FAILURE( + SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp)); + ODK_ProvisioningRequest core_request = { + .api_minor_version = ODK_MINOR_VERSION, + .api_major_version = ODK_MAJOR_VERSION, + .nonce = 0xdeadbeef, + .session_id = 0xcafebabe, + }; + const CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION); + std::string oemcrypto_core_message; + EXPECT_TRUE(CreateCoreProvisioningResponseFromProto( + features, serialized_provisioning_resp, core_request, + OEMCrypto_RSA_Private_Key, &oemcrypto_core_message)); +} + +// Verify de-serialize common request. +TEST(OdkTest, ParseCoreCommonRequestFromMessage) { + std::string serialized_provisioning_resp; + EXPECT_NO_FATAL_FAILURE( + SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp)); + ODK_ProvisioningRequest core_request = { + .api_minor_version = ODK_MINOR_VERSION, + .api_major_version = ODK_MAJOR_VERSION, + .nonce = 0xdeadbeef, + .session_id = 0xcafebabe, + }; + const CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION); + std::string oemcrypto_core_message; + EXPECT_TRUE(CreateCoreProvisioningResponseFromProto( + features, serialized_provisioning_resp, core_request, + OEMCrypto_RSA_Private_Key, &oemcrypto_core_message)); + ODK_CommonRequest odk_common_request; + ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message, + &odk_common_request)); + EXPECT_EQ(odk_common_request.message_type, 6u); + EXPECT_EQ(odk_common_request.message_length, 48u); + EXPECT_EQ(odk_common_request.api_minor_version, ODK_MINOR_VERSION); + EXPECT_EQ(odk_common_request.api_major_version, ODK_MAJOR_VERSION); + EXPECT_EQ(odk_common_request.nonce, 0xdeadbeef); + EXPECT_EQ(odk_common_request.session_id, 0xcafebabe); } class OdkVersionTest : public ::testing::Test, @@ -735,8 +947,12 @@ class OdkVersionTest : public ::testing::Test, GetParam().response_major_version; params->core_message.nonce_values.api_minor_version = GetParam().response_minor_version; - features_ = - CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version); + if (GetParam().maximum_major_version > 0) { + features_ = CoreMessageFeatures::DefaultFeatures( + GetParam().maximum_major_version); + } else { + features_ = CoreMessageFeatures::kDefaultFeatures; + } } CoreMessageFeatures features_; }; @@ -756,9 +972,9 @@ TEST_P(OdkVersionTest, LicenseResponseRoundtrip) { auto odk_parse_func = [&](const uint8_t* buf, size_t size) { return ODK_ParseLicense( buf, size + kExtraPayloadSize, size, params.initial_license_load, - params.usage_entry_present, &(params.timer_limits), + params.usage_entry_present, 0, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), - &(params.parsed_license)); + &(params.parsed_license), nullptr); }; const std::string request_hash_string( reinterpret_cast(request_hash_read), @@ -806,7 +1022,8 @@ TEST_P(OdkVersionTest, RenewalResponseRoundtrip) { TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { ODK_ProvisioningResponseParams params; - ODK_SetDefaultProvisioningResponseParams(¶ms); + ODK_SetDefaultProvisioningResponseParams(¶ms, + GetParam().response_major_version); SetRequestVersion(¶ms); // save a copy of params.device_id as it will be zero out during the test const uint32_t device_id_length = params.device_id_length; @@ -821,8 +1038,12 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { }; auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message) { + // use device_id for V17 and V16 core_request.device_id.assign(reinterpret_cast(device_id), device_id_length); + // use counter info for V18 + memcpy(&core_request.counter_info, ¶ms.counter_info, + sizeof(params.counter_info)); return CreateCoreProvisioningResponse(features_, params.parsed_provisioning, core_request, oemcrypto_core_message); }; @@ -831,12 +1052,30 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { kdo_prepare_func); } +TEST_P(OdkVersionTest, Provision40ResponseRoundtrip) { + ODK_Provisioning40ResponseParams params; + ODK_SetDefaultProvisioning40ResponseParams(¶ms); + SetRequestVersion(¶ms); + + auto odk_parse_func = [&](const uint8_t* buf, size_t size) { + OEMCryptoResult err = ODK_ParseProvisioning40( + buf, size + 16, size, &(params.core_message.nonce_values)); + return err; + }; + auto kdo_prepare_func = [&](ODK_Provisioning40Request& core_request, + std::string* oemcrypto_core_message) { + return CreateCoreProvisioning40Response(features_, core_request, + oemcrypto_core_message); + }; + ValidateResponse( + GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, + kdo_prepare_func); +} + // If the minor version is positive, we can test an older minor version. const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0; // Similarly, if this isn't the first major version, we can test an older major // version. -// TODO(b/163416999): Remove it in the future. This will be unecessarily -// complicated after we upgrade to version 17. const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? ODK_MAJOR_VERSION - 1 : ODK_FIRST_VERSION; @@ -862,16 +1101,24 @@ std::vector TestCases() { {ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor}, // If the server is restricted to v16, then the response can be at // most 16.5 + // These tests cases must be updated whenever we roll the minor version + // number. {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, 1}, // Here are some known good versions. Make extra sure they work. - {16, 16, 3, 16, 3}, - {16, 16, 4, 16, 4}, - {16, 16, 5, 16, 5}, - {17, 16, 3, 16, 3}, - {17, 16, 4, 16, 4}, - {17, 16, 5, 16, 5}, - {17, 17, 0, 17, 0}, - {17, 17, 1, 17, 1}, + {ODK_MAJOR_VERSION, 16, 3, 16, 3}, + {ODK_MAJOR_VERSION, 16, 4, 16, 4}, + {ODK_MAJOR_VERSION, 16, 5, 16, 5}, + {ODK_MAJOR_VERSION, 17, 1, 17, 1}, + {ODK_MAJOR_VERSION, 17, 2, 17, 2}, + {ODK_MAJOR_VERSION, 18, 0, 18, 0}, + {0, 16, 3, 16, 3}, + {0, 16, 4, 16, 4}, + {0, 16, 5, 16, 5}, + {0, 17, 1, 17, 1}, + {0, 17, 2, 17, 2}, + {0, 18, 0, 17, 2}, // Change to 18 when the default version is updated. }; return test_cases; } @@ -887,11 +1134,14 @@ TEST(OdkSizeTest, LicenseRequest) { uint16_t api_major_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreLicenseRequest(message, message_length, - &core_message_length, &nonce_values)); + &core_message_length, &nonce_values, + &counter_info)); // the core_message_length should be appropriately set EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE, core_message_length); } @@ -948,13 +1198,14 @@ TEST(OdkSizeTest, ProvisioningRequest) { uint16_t api_major_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; - uint32_t device_id_length = 0; + ODK_MessageCounterInfo counter_info; + memset(&counter_info, 0, sizeof(counter_info)); ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - ODK_PrepareCoreProvisioningRequest( - message, message_length, &core_message_length, &nonce_values, - nullptr, device_id_length)); + ODK_PrepareCoreProvisioningRequest(message, message_length, + &core_message_length, + &nonce_values, &counter_info)); // the core_message_length should be appropriately set EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length); } diff --git a/oemcrypto/odk/test/odk_test_helper.cpp b/oemcrypto/odk/test/odk_test_helper.cpp index dab9afa..db9b2f2 100644 --- a/oemcrypto/odk/test/odk_test_helper.cpp +++ b/oemcrypto/odk/test/odk_test_helper.cpp @@ -8,7 +8,10 @@ #include #include #include +#include +#include #include +#include #include #include @@ -75,6 +78,7 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, .length = 3, .data = {0, 0, 0}, }}, + .renewal_delay_base = OEMCrypto_License_Start, .key_array_length = 3, .key_array = { @@ -203,6 +207,11 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, ".cmi_descriptor_data"}); } } + if (odk_major_version >= 18) { + params->extra_fields.push_back( + {ODK_UINT32, &(params->parsed_license.renewal_delay_base), + ".renewal_delay_base"}); + } params->extra_fields.push_back({ODK_UINT32, &(params->parsed_license.key_array_length), ".key_array_length"}); @@ -288,7 +297,7 @@ void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) { } void ODK_SetDefaultProvisioningResponseParams( - ODK_ProvisioningResponseParams* params) { + ODK_ProvisioningResponseParams* params, uint32_t odk_major_version) { ODK_SetDefaultCoreFields(&(params->core_message), ODK_Provisioning_Response_Type); params->device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; @@ -301,17 +310,34 @@ void ODK_SetDefaultProvisioningResponseParams( .enc_private_key_iv = {.offset = 2, .length = 3}, .encrypted_message_key = {.offset = 4, .length = 5}, }; - params->extra_fields = { - {ODK_UINT32, &(params->device_id_length), "device_id_length"}, - {ODK_DEVICEID, params->device_id, "device_id"}, - {ODK_UINT32, &(params->parsed_provisioning).key_type, "key_type"}, + + params->extra_fields = {}; + // V17 uses device_id + if (odk_major_version <= 17) { + params->extra_fields.push_back( + {ODK_UINT32, &(params->device_id_length), "device_id_length"}); + params->extra_fields.push_back( + {ODK_DEVICEID, params->device_id, "device_id"}); + } + + params->extra_fields.push_back( + {ODK_UINT32, &(params->parsed_provisioning).key_type, "key_type"}); + params->extra_fields.push_back( {ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key, - "enc_private_key"}, + "enc_private_key"}); + params->extra_fields.push_back( {ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key_iv, - "enc_private_key_iv"}, + "enc_private_key_iv"}); + params->extra_fields.push_back( {ODK_SUBSTRING, &(params->parsed_provisioning).encrypted_message_key, - "encrypted_message_key"}, - }; + "encrypted_message_key"}); +} + +void ODK_SetDefaultProvisioning40ResponseParams( + ODK_Provisioning40ResponseParams* params) { + ODK_SetDefaultCoreFields(&(params->core_message), + ODK_Provisioning_Response_Type); + params->extra_fields = {}; } size_t ODK_FieldLength(ODK_FieldType type) { @@ -330,6 +356,10 @@ size_t ODK_FieldLength(ODK_FieldType type) { return sizeof(uint32_t) + sizeof(uint32_t); case ODK_DEVICEID: return ODK_DEVICE_ID_LEN_MAX; + case ODK_MESSAGECOUNTER: + return ODK_MESSAGECOUNTERINFO_SIZE; + case ODK_DEVICEINFO: + return ODK_DEVICE_INFO_LEN_MAX; case ODK_RENEWALDATA: return ODK_KEYBOX_RENEWAL_DATA_SIZE; case ODK_HASH: @@ -343,6 +373,9 @@ size_t ODK_AllocSize(ODK_FieldType type) { if (type == ODK_SUBSTRING) { return sizeof(OEMCrypto_Substring); } + if (type == ODK_MESSAGECOUNTER) { + return sizeof(ODK_MessageCounterInfo); + } return ODK_FieldLength(type); } @@ -388,6 +421,7 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) { break; } case ODK_DEVICEID: + case ODK_DEVICEINFO: case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); @@ -396,6 +430,27 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) { break; } + case ODK_MESSAGECOUNTER: { + // Size required in field->value, which may get padding from the compiler. + const size_t src_len = ODK_AllocSize(field->type); + // Size taken up in serialized message buffer, which is tightly packed. + const size_t dest_len = ODK_FieldLength(field->type); + const uint8_t* const write_src = static_cast(field->value); + + // Copy data from field to buf, fixing endian-ness + ODK_MessageCounterInfo info; + memcpy(&info, write_src, src_len); + info.master_generation_number = + oemcrypto_htobe64(info.master_generation_number); + info.provisioning_count = oemcrypto_htobe32(info.provisioning_count); + info.license_count = oemcrypto_htobe32(info.license_count); + info.decrypt_count = oemcrypto_htobe32(info.decrypt_count); + info.major_version = oemcrypto_htobe16(info.major_version); + info.minor_version = oemcrypto_htobe16(info.minor_version); + info.patch_version = oemcrypto_htobe16(info.patch_version); + memcpy(buf, &info, dest_len); + break; + } default: return ODK_ERROR_CORE_MESSAGE; } @@ -448,6 +503,7 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, break; } case ODK_DEVICEID: + case ODK_DEVICEINFO: case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); @@ -455,6 +511,55 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, memcpy(id, buf, field_len); break; } + case ODK_MESSAGECOUNTER: { + // Size required in field->value, which may get padding from the compiler. + const size_t dest_len = ODK_AllocSize(field->type); + // Size taken up in serialized message buffer, which is tightly packed. + const size_t src_len = ODK_FieldLength(field->type); + uint8_t* const read_dest = static_cast(field->value); + + // Copy data from buf to field, fixing endian-ness + uint8_t temp_buf[sizeof(ODK_MessageCounterInfo)] = {0}; + memcpy(temp_buf, buf, src_len); + + size_t index = 0; + ODK_MessageCounterInfo info; + uint64_t* u64 = reinterpret_cast(&temp_buf[index]); + info.master_generation_number = oemcrypto_be64toh(*u64); + index += sizeof(uint64_t); + + uint32_t* u32 = reinterpret_cast(&temp_buf[index]); + info.provisioning_count = oemcrypto_be32toh(*u32); + index += sizeof(uint32_t); + + u32 = reinterpret_cast(&temp_buf[index]); + info.license_count = oemcrypto_be32toh(*u32); + index += sizeof(uint32_t); + + u32 = reinterpret_cast(&temp_buf[index]); + info.decrypt_count = oemcrypto_be32toh(*u32); + index += sizeof(uint32_t); + + uint16_t* u16 = reinterpret_cast(&temp_buf[index]); + info.major_version = oemcrypto_be16toh(*u16); + index += sizeof(uint16_t); + + u16 = reinterpret_cast(&temp_buf[index]); + info.minor_version = oemcrypto_be16toh(*u16); + index += sizeof(uint16_t); + + u16 = reinterpret_cast(&temp_buf[index]); + info.patch_version = oemcrypto_be16toh(*u16); + index += sizeof(uint16_t); + + memcpy(info.soc_vendor, &temp_buf[index], sizeof(info.soc_vendor)); + index += sizeof(info.soc_vendor); + memcpy(info.chipset_model, &temp_buf[index], sizeof(info.chipset_model)); + index += sizeof(info.chipset_model); + memcpy(info.extra, &temp_buf[index], sizeof(info.extra)); + memcpy(read_dest, &info, dest_len); + break; + } default: return ODK_ERROR_CORE_MESSAGE; } @@ -508,6 +613,8 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, break; } case ODK_DEVICEID: + case ODK_MESSAGECOUNTER: + case ODK_DEVICEINFO: case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); diff --git a/oemcrypto/odk/test/odk_test_helper.h b/oemcrypto/odk/test/odk_test_helper.h index f825af1..b004233 100644 --- a/oemcrypto/odk/test/odk_test_helper.h +++ b/oemcrypto/odk/test/odk_test_helper.h @@ -21,6 +21,8 @@ enum ODK_FieldType { ODK_UINT64, ODK_SUBSTRING, ODK_DEVICEID, + ODK_DEVICEINFO, + ODK_MESSAGECOUNTER, ODK_RENEWALDATA, ODK_HASH, // The "stressable" types are the ones we can put in a stress test that packs @@ -71,10 +73,17 @@ struct ODK_ProvisioningResponseParams { ODK_CoreMessage core_message; uint8_t device_id[ODK_DEVICE_ID_LEN_MAX]; uint32_t device_id_length; + uint32_t padding_u32; + ODK_MessageCounterInfo counter_info; ODK_ParsedProvisioning parsed_provisioning; std::vector extra_fields; }; +struct ODK_Provisioning40ResponseParams { + ODK_CoreMessage core_message; + std::vector extra_fields; +}; + // Default values in core_message for testing void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message, ODK_MessageType message_type); @@ -82,7 +91,9 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, uint32_t odk_major_version); void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params); void ODK_SetDefaultProvisioningResponseParams( - ODK_ProvisioningResponseParams* params); + ODK_ProvisioningResponseParams* params, uint32_t odk_major_version); +void ODK_SetDefaultProvisioning40ResponseParams( + ODK_Provisioning40ResponseParams* params); size_t ODK_FieldLength(ODK_FieldType type); size_t ODK_AllocSize(ODK_FieldType type); @@ -92,8 +103,8 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field); // Load buf to ODK_Field OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, const ODK_Field* field); OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, const ODK_Field* field); -OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf, - const size_t size_in, size_t* size_out, +OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf, size_t size_in, + size_t* size_out, const std::vector& fields); void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n, const std::vector& fields); diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp index 8413960..b595d98 100644 --- a/oemcrypto/odk/test/odk_timer_test.cpp +++ b/oemcrypto/odk/test/odk_timer_test.cpp @@ -6,7 +6,9 @@ #include "OEMCryptoCENCCommon.h" #include "gtest/gtest.h" #include "odk.h" +#include "odk_structs.h" #include "odk_structs_priv.h" +#include "odk_test_helper.h" namespace { @@ -23,6 +25,99 @@ constexpr uint64_t kRentalClockStart = 1000u; // renewal is not loaded. constexpr uint64_t kGracePeriod = 5u; +constexpr uint32_t kExtraPayloadSize = 128u; + +constexpr uint32_t kSystemTime = 20u; + +namespace wvodk_test { + +TEST(OdkTimerBasicTest, ParseLicenseTimerSet) { + // playback timer is successfully started + ::wvodk_test::ODK_LicenseResponseParams params; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.renewal_delay_base = OEMCrypto_License_Load; + params.parsed_license.timer_limits.soft_enforce_rental_duration = false; + params.parsed_license.timer_limits.soft_enforce_playback_duration = false; + params.parsed_license.timer_limits.earliest_playback_start_seconds = 10; + params.parsed_license.timer_limits.total_playback_duration_seconds = 0; + params.parsed_license.timer_limits.rental_duration_seconds = 10; + params.parsed_license.timer_limits.initial_renewal_duration_seconds = 0; + OEMCryptoResult result = + ODK_InitializeClockValues(¶ms.clock_values, kSystemTime); + EXPECT_EQ(OEMCrypto_SUCCESS, result); + params.clock_values.time_of_license_request_signed = 5; + params.clock_values.status = kActive; + + uint8_t* buf = nullptr; + uint32_t buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + + result = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, kSystemTime, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license), nullptr); + EXPECT_EQ(ODK_SET_TIMER, result); + delete[] buf; +} + +TEST(OdkTimerBasicTest, ParseLicenseTimerDisabled) { + // playback timer is successfully started + ::wvodk_test::ODK_LicenseResponseParams params; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.renewal_delay_base = OEMCrypto_License_Load; + params.parsed_license.timer_limits.soft_enforce_rental_duration = true; + params.parsed_license.timer_limits.earliest_playback_start_seconds = 3; + params.parsed_license.timer_limits.total_playback_duration_seconds = 0; + params.parsed_license.timer_limits.initial_renewal_duration_seconds = 0; + params.clock_values.time_of_first_decrypt = 10; + params.clock_values.time_of_license_request_signed = 5; + params.clock_values.status = kActive; + + uint8_t* buf = nullptr; + uint32_t buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + + OEMCryptoResult result = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, kSystemTime, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license), nullptr); + EXPECT_EQ(ODK_DISABLE_TIMER, result); + delete[] buf; +} + +TEST(OdkTimerBasicTest, ParseRenewalTimerExpired) { + // playback timer is successfully started + ::wvodk_test::ODK_LicenseResponseParams params; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + + params.parsed_license.renewal_delay_base = OEMCrypto_License_Load; + params.parsed_license.timer_limits.rental_duration_seconds = 5; + params.parsed_license.timer_limits.earliest_playback_start_seconds = 3; + OEMCryptoResult result = + ODK_InitializeClockValues(¶ms.clock_values, kSystemTime); + EXPECT_EQ(OEMCrypto_SUCCESS, result); + params.clock_values.time_of_license_request_signed = 5; + + uint8_t* buf = nullptr; + uint32_t buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + + result = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, kSystemTime, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license), nullptr); + EXPECT_EQ(ODK_TIMER_EXPIRED, result); + delete[] buf; +} + +} // namespace wvodk_test + TEST(OdkTimerBasicTest, NullTest) { // Assert that nullptr does not cause a core dump. ODK_InitializeClockValues(nullptr, 0u); diff --git a/oemcrypto/oemcrypto_security_tests.gyp b/oemcrypto/oemcrypto_security_tests.gyp new file mode 100644 index 0000000..24fa2b9 --- /dev/null +++ b/oemcrypto/oemcrypto_security_tests.gyp @@ -0,0 +1,51 @@ +# This is a gyp file for building the OEMCrypto unit tests with the reference +# code from the stand-alone source code. +{ + 'variables': { + # Override the variables below for the location of various gyp files. + # Alternatively, set the environment variable PATH_TO_CDM_DIR to point to a + # recent version of the source CDM. This *must* be a relative path. + 'privacy_crypto_impl%': 'boringssl', + 'boringssl_libcrypto_path%': 'drm_private_key); - if (result == OEMCrypto_SUCCESS) result = free_key_result; + // TODO(b/225216277): When result is not OEMCrypto_ERROR_NOT_IMPLEMENTED + // above, uncomment this check + // if (result == OEMCrypto_SUCCESS) + result = free_key_result; free_key_result = FreeMacAndEncryptionKeys(session_context); - if (result == OEMCrypto_SUCCESS) result = free_key_result; + // TODO(b/225216277): When result is not OEMCrypto_ERROR_NOT_IMPLEMENTED + // above, uncomment this check + // if (result == OEMCrypto_SUCCESS) + result = free_key_result; if (result != OEMCrypto_SUCCESS) session_context->state = SESSION_INVALID; return result; } @@ -247,11 +255,11 @@ static OEMCryptoResult RewrapDeviceDRMKeyCommon(OEMCryptoSession* session, result); return result; } - size_t private_key_size; - result = WTPI_GetSignatureSize(private_key_handle, &private_key_size); + size_t signature_size; + result = WTPI_GetSignatureSize(private_key_handle, &signature_size); WTPI_FreeAsymmetricKeyHandle(private_key_handle); if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to get DRM private key size with result: %u", result); + LOGE("Failed to get DRM key signature size with result: %u", result); return result; } @@ -263,9 +271,9 @@ static OEMCryptoResult RewrapDeviceDRMKeyCommon(OEMCryptoSession* session, return result; } /* Check that it's a valid DRM key. */ - result = OPKI_LoadDRMKey(session, drm_key_type, wrapped_drm_key, - wrapped_drm_key_length, private_key_size, - allowed_schemes); + result = + OPKI_LoadDRMKey(session, drm_key_type, wrapped_drm_key, + wrapped_drm_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to load DRM key with result: %u", result); } @@ -420,7 +428,13 @@ OEMCryptoResult OEMCrypto_Initialize(void) { LOGE("OEMCrypto will now terminate and re-initialize."); OEMCrypto_Terminate(); } - + if (API_MAJOR_VERSION != ODK_MAJOR_VERSION || + API_MINOR_VERSION != ODK_MINOR_VERSION) { + // If this error happens, you should probably change the API version in + // oemcrypto_api_macros.h. + LOGE("Using ODK v%d.%d with OPK v%d.%d", ODK_MAJOR_VERSION, + ODK_MINOR_VERSION, API_MAJOR_VERSION, API_MINOR_VERSION); + } OEMCryptoResult result = WTPI_Initialize(); if (result != OEMCrypto_SUCCESS) { LOGE("OEMCrypto failed to |WTPI_Initialize| with result: %u", result); @@ -464,6 +478,15 @@ OEMCryptoResult OEMCrypto_Initialize(void) { goto cleanup; } + memset(&g_counter_info, 0, sizeof(g_counter_info)); + g_counter_info.major_version = API_MAJOR_VERSION; + g_counter_info.minor_version = API_MINOR_VERSION; + g_counter_info.patch_version = OPK_PATCH_VERSION; + strncpy((char*)g_counter_info.soc_vendor, XSTR(OPK_CONFIG_SOC_VENDOR_NAME), + sizeof(g_counter_info.soc_vendor)); + strncpy((char*)g_counter_info.chipset_model, XSTR(OPK_CONFIG_SOC_MODEL_NAME), + sizeof(g_counter_info.chipset_model)); + g_opk_system_state = SYSTEM_INITIALIZED; result = OEMCrypto_SUCCESS; @@ -473,6 +496,10 @@ cleanup: return result; } +OEMCryptoResult OEMCrypto_SetMaxAPIVersion(uint32_t max_version UNUSED) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + OEMCryptoResult OEMCrypto_Terminate(void) { OEMCryptoResult usage_table_terminate_result = OPKI_TerminateUsageTable(); OEMCryptoResult entitled_key_session_terminate_result = @@ -673,10 +700,11 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( size_t session_key_length = sizeof(session_key); size_t expected_session_key_length = 0; result = OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED; - if (session_context->drm_private_key == NULL) goto cleanup; WTPI_AsymmetricKey_Handle private_key_handle; uint32_t allowed_schemes; - AsymmetricKey* private_key = session_context->drm_private_key; + AsymmetricKey* private_key; + if (session_context->drm_private_key == NULL) goto cleanup; + private_key = session_context->drm_private_key; result = WTPI_UnwrapIntoAsymmetricKeyHandle( private_key->wrapped_key, private_key->wrapped_key_length, private_key->key_type, &private_key_handle, &allowed_schemes); @@ -790,10 +818,11 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, /* last_nonce_time should only be initialized once. */ static uint64_t last_nonce_time = 0; static int nonce_count = 0; - const int nonce_flood_count = 200; + const int kNonceFloodCount = 200; if (last_nonce_time == now) { - nonce_count++; - if (nonce_count > nonce_flood_count) { + if (nonce_count < kNonceFloodCount) { + nonce_count++; + } else { LOGE("Nonce flood detected: now = %" PRIu64, now); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -848,19 +877,36 @@ OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + const OEMCrypto_ProvisioningMethod provisioning_method = + WTPI_GetProvisioningMethod(); size_t required_signature_size; - result = GetROTSignatureLength(&required_signature_size); - if (result != OEMCrypto_SUCCESS) return result; - uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; - size_t device_id_length = ODK_DEVICE_ID_LEN_MAX; - result = GetDeviceID(device_id, &device_id_length); - if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to get device id with result: %u", result); - return result; + if (provisioning_method == OEMCrypto_BootCertificateChain) { + if (session_context->prov40_csr_signing_key == NULL) { + LOGE("Provisioning 4 request signing key is not loaded"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + required_signature_size = + session_context->prov40_csr_signing_key->signature_size; + uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0}; + size_t device_info_length = sizeof(device_info); + result = WTPI_GetDeviceInformation(device_info, &device_info_length); + if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + device_info_length = 0; + } else if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get device information with result: %u", result); + return result; + } + result = ODK_PrepareCoreProvisioning40Request( + message, message_length, core_message_length, + &session_context->nonce_values, device_info, device_info_length, + &g_counter_info); + } else { + result = GetROTSignatureLength(&required_signature_size); + if (result != OEMCrypto_SUCCESS) return result; + result = ODK_PrepareCoreProvisioningRequest( + message, message_length, core_message_length, + &session_context->nonce_values, &g_counter_info); } - result = ODK_PrepareCoreProvisioningRequest( - message, message_length, core_message_length, - &session_context->nonce_values, device_id, device_id_length); if (*signature_length < required_signature_size || result == OEMCrypto_ERROR_SHORT_BUFFER) { *signature_length = required_signature_size; @@ -876,11 +922,13 @@ OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( RETURN_INVALID_CONTEXT_IF_NULL(message); RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(signature); - const OEMCrypto_ProvisioningMethod provisioning_method = - WTPI_GetProvisioningMethod(); if (provisioning_method == OEMCrypto_Keybox) { result = OPKI_GenerateSignatureWithMacKeyClient( session_context, message, message_length, signature, signature_length); + } else if (provisioning_method == OEMCrypto_BootCertificateChain) { + result = OPKI_GenerateCertSignature(session_context, message, + message_length, signature, + signature_length, CERT_SIGNATURE_CSR); } else if (provisioning_method == OEMCrypto_OEMCertificate) { result = OPKI_GenerateCertSignature(session_context, message, message_length, signature, @@ -896,6 +944,7 @@ OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( return result; } session_context->request_signed = true; + g_counter_info.provisioning_count++; return OPKI_SetStatePostCall(session_context, API_PREPANDSIGN_PROVISION_REQUEST); } @@ -926,10 +975,11 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( RETURN_INVALID_CONTEXT_IF_NULL(core_message_length); RETURN_INVALID_CONTEXT_IF_NULL(signature_length); ABORT_IF_NULL(session_context->drm_private_key); - size_t required_signature_size = session_context->drm_private_key->key_size; - result = ODK_PrepareCoreLicenseRequest(message, message_length, - core_message_length, - &session_context->nonce_values); + size_t required_signature_size = + session_context->drm_private_key->signature_size; + result = ODK_PrepareCoreLicenseRequest( + message, message_length, core_message_length, + &session_context->nonce_values, &g_counter_info); if (*signature_length < required_signature_size || result == OEMCrypto_ERROR_SHORT_BUFFER) { *signature_length = required_signature_size; @@ -982,6 +1032,7 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( return result; } session_context->request_signed = true; + g_counter_info.license_count++; return OPKI_SetStatePostCall(session_context, API_PREPANDSIGN_LICENSE_REQUEST); } @@ -1364,12 +1415,25 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, const bool usage_entry_present = (OPKI_GetUsageEntryStatus(session_context->session_id) != USAGE_ENTRY_NONE); - result = ODK_ParseLicense(message, message_length, core_message_length, - initial_license_load, usage_entry_present, - &session_context->timer_limits, - &session_context->clock_values, - &session_context->nonce_values, &parsed_response); + uint64_t now; + result = WTPI_GetTrustedTime(&now); if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get trusted time with result: %u", result); + return result; + } + result = ODK_ParseLicense( + message, message_length, core_message_length, initial_license_load, + usage_entry_present, now, &session_context->timer_limits, + &session_context->clock_values, &session_context->nonce_values, + &parsed_response, NULL); + if (result == ODK_TIMER_EXPIRED) { + LOGE( + "Failed to parse license because license is attempted to be loaded " + "after the rental duration expires"); + return OEMCrypto_ERROR_KEY_EXPIRED; + } else if (result == ODK_SET_TIMER || result == ODK_DISABLE_TIMER) { + session_context->decrypt_started = true; + } else if (result != OEMCrypto_SUCCESS) { LOGE("Failed to parse license with result: %u", result); return result; } @@ -1849,14 +1913,22 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, return OPKI_SetStatePostCall(session_context, API_QUERYKEYCONTROL); } -OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, - const uint8_t* content_key_id, - size_t content_key_id_length, - OEMCryptoCipherMode cipher_mode) { +OEMCryptoResult OEMCrypto_GetKeyHandle(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, + uint8_t* key_handle, + size_t* key_handle_length) { + // Mostly the same as OEMCrypto_SelectKey() with a few differences + // - use platform-specific key handle export if supported + // - export session as key handle otherwise + // - update timers + if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + OEMCryptoSession* session_context = NULL; OEMCryptoEntitledKeySession* key_session = NULL; OEMCryptoResult result = @@ -1864,9 +1936,10 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, if (result != OEMCrypto_SUCCESS) return result; ABORT_IF(session_context == NULL, "GetSessionContext() provided invalid output."); - result = OPKI_CheckStatePreCall(session_context, API_SELECTKEY); + result = OPKI_CheckStatePreCall(session_context, API_GETKEYHANDLE); if (result != OEMCrypto_SUCCESS) return result; + RETURN_INVALID_CONTEXT_IF_NULL(key_handle_length); RETURN_INVALID_CONTEXT_IF_NULL(content_key_id); RETURN_INVALID_CONTEXT_IF_ZERO(content_key_id_length); if (content_key_id_length > KEY_ID_MAX_SIZE) { @@ -1896,15 +1969,14 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, content_key_id_length); } if (!content_key) return OEMCrypto_ERROR_NO_CONTENT_KEY; + KeyControlBlock key_control_block; result = OPKI_GetKeyControlBlock(content_key, session_context, key_session, &key_control_block); if (result != OEMCrypto_SUCCESS) return result; - if (WTPI_HasAnalogDisplay() && WTPI_SupportsCGMS_A() && - (key_control_block.control_bits & CONTROL_OBSERVE_CGMS)) { - result = WTPI_ApplyCGMS(key_control_block.control_bits & CONTROL_CGMS_MASK); - if (result != OEMCrypto_SUCCESS) return result; - } + result = OPKI_EnforceOutputRestrictions(key_control_block); + if (result != OEMCrypto_SUCCESS) return result; + if (session_type == SESSION_TYPE_ENTITLED_KEY) { key_session->current_entitled_content_key_index = content_key->session_key_index; @@ -1913,11 +1985,27 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, } content_key->cipher_mode = cipher_mode; - return OPKI_SetStatePostCall(session_context, API_SELECTKEY); + // So far this has been almost the exact same as OEMCrypto_SelectKey() + result = OPKI_UpdatePlaybackTimeAndUsageEntryStatus(session_context); + if (result != OEMCrypto_SUCCESS) return result; + + if (WTPI_ContentDecryptBypassesTA()) { + result = WTPI_K1_PrepareExternalKeyHandle(content_key->key_handle, + key_handle, key_handle_length); + if (result != OEMCrypto_SUCCESS) return result; + } else { + if (key_handle == NULL || *key_handle_length < sizeof(OEMCrypto_SESSION)) { + *key_handle_length = sizeof(OEMCrypto_SESSION); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(key_handle, &session, sizeof(session)); + } + + return OPKI_SetStatePostCall(session_context, API_GETKEYHANDLE); } -/* This function will only be called if at least some of the data is encrypted, - meaning this function can assume a key is required. */ +/* This function will only be called if at least some of the data is + encrypted, meaning this function can assume a key is required. */ static OEMCryptoResult DecryptCENCInternal( OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) { @@ -1937,9 +2025,50 @@ static OEMCryptoResult DecryptCENCInternal( RETURN_INVALID_CONTEXT_IF_ZERO(samples_length); RETURN_INVALID_CONTEXT_IF_NULL(pattern); + result = OPKI_DecryptSamples(session_context, key_session, samples, + samples_length, pattern); + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + /* OPKI_DecryptSamples may pass back an OEMCrypto_ERROR_SHORT_BUFFER that + originated in OPK_CheckOutputBounds(). This is not a valid return code + for DecryptCENC(), so we translate it here. */ + LOGE("Output buffer size is too small"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } else if (result != OEMCrypto_SUCCESS) { + return result; + } + + return OPKI_SetStatePostCall(session_context, API_DECRYPTCENC); +} + +OEMCryptoResult OEMCrypto_DecryptCENC( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + if (WTPI_ContentDecryptBypassesTA()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_handle); + RETURN_INVALID_CONTEXT_IF_NULL(samples); + RETURN_INVALID_CONTEXT_IF_ZERO(samples_length); + RETURN_INVALID_CONTEXT_IF_NULL(pattern); + + // take key handle, transform to session id + if (key_handle_length < sizeof(OEMCrypto_SESSION)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCrypto_SESSION session; + memcpy(&session, key_handle, sizeof(session)); + + bool has_encrypted_data = false; const size_t max_length = WTPI_MaxSampleSize(); - /* Iterate through all the samples and validate them before doing any decrypt. - */ + /* Iterate through all the samples and validate them before doing any + * decrypt or copy over. Also it checks whether there is any encrypted data + * in the samples. */ for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { const OEMCrypto_SampleDescription* const sample = &(samples[sample_index]); if (sample->buffers.input_data == NULL || @@ -1962,6 +2091,7 @@ static OEMCryptoResult DecryptCENCInternal( &subsample_length_tally)) { return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } + if (subsample->num_bytes_encrypted > 0) has_encrypted_data = true; } if (max_length != 0 && subsample_length_tally > max_length) { return OEMCrypto_ERROR_BUFFER_TOO_LARGE; @@ -1973,74 +2103,36 @@ static OEMCryptoResult DecryptCENCInternal( } } - result = OPKI_DecryptSamples(session_context, key_session, samples, - samples_length, pattern); - if (result == OEMCrypto_ERROR_SHORT_BUFFER) { - /* OPKI_DecryptSamples may pass back an OEMCrypto_ERROR_SHORT_BUFFER that - originated in OPK_CheckOutputBounds(). This is not a valid return code - for DecryptCENC(), so we translate it here. */ - LOGE("Output buffer size is too small"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } else if (result != OEMCrypto_SUCCESS) { - return result; - } - - return OPKI_SetStatePostCall(session_context, API_DECRYPTCENC); -} - -OEMCryptoResult OEMCrypto_DecryptCENC( - OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, - size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) { - if (g_opk_system_state != SYSTEM_INITIALIZED) { - LOGE("OEMCrypto is not yet initialized"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - RETURN_INVALID_CONTEXT_IF_NULL(samples); - RETURN_INVALID_CONTEXT_IF_ZERO(samples_length); - RETURN_INVALID_CONTEXT_IF_NULL(pattern); /* DecryptCENC may be called for calls that could go through CopyBuffer. We separate those calls out here so that the decrypt code path only has to handle cases where a key is expected. */ - bool has_encrypted_data = false; - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - if (samples[sample_index].subsamples_length != 1 || - samples[sample_index].subsamples[0].num_bytes_encrypted > 0) { - has_encrypted_data = true; - break; - } - } - if (has_encrypted_data) - return DecryptCENCInternal(session, samples, samples_length, pattern); - - const size_t max_length = WTPI_MaxSampleSize(); - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - const OEMCrypto_SampleDescription* const sample = &(samples[sample_index]); - ABORT_IF(sample->subsamples_length != 1, - "Sample %zu with multiple subsamples was somehow not treated as " - "encrypted.", - sample_index); - const OEMCrypto_SubSampleDescription* const subsample = - &(sample->subsamples[0]); - if (max_length != 0 && subsample->num_bytes_clear > max_length) { - LOGE("Sample size too large: %zu bytes. Max allowed: %zu", - subsample->num_bytes_clear, max_length); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - if (subsample->num_bytes_clear != sample->buffers.input_data_length) { - LOGE("Sample %zu's length and subsample length do not match.", - sample_index); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - OEMCryptoResult result = OEMCrypto_CopyBuffer( - session, sample->buffers.input_data, sample->buffers.input_data_length, - &sample->buffers.output_descriptor, subsample->subsample_flags); + if (has_encrypted_data) { + const OEMCryptoResult result = + DecryptCENCInternal(session, samples, samples_length, pattern); if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to copy buffer with result: %u", result); + LOGE("Failed to decrypt samples with result: %u", result); return result; } + } else { + /* Handle clear samples. */ + for (size_t sample_index = 0; sample_index < samples_length; + ++sample_index) { + const OEMCrypto_SampleDescription* const sample = + &(samples[sample_index]); + /* Copy the consecutive subsamples all at once. */ + const OEMCryptoResult result = OEMCrypto_CopyBuffer( + session, sample->buffers.input_data, + sample->buffers.input_data_length, + &sample->buffers.output_descriptor, /*subsample_flags=*/ + (OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to copy buffer with result: %u", result); + return result; + } + } } + + g_counter_info.decrypt_count++; return OEMCrypto_SUCCESS; } @@ -2077,12 +2169,47 @@ OEMCryptoResult OEMCrypto_CopyBuffer( } OEMCryptoResult OEMCrypto_Generic_Encrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + + if (WTPI_ContentDecryptBypassesTA()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_handle); + RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); + RETURN_INVALID_CONTEXT_IF_NULL(out_buffer); + RETURN_INVALID_CONTEXT_IF_ZERO(in_buffer_length); + RETURN_INVALID_CONTEXT_IF_NULL(iv); + + if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { + LOGE("Invalid algorithm."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (in_buffer_length % AES_BLOCK_SIZE != 0) { + LOGE( + "in_buffer_length of %zu is not a multiple of the crypto block length.", + in_buffer_length); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + size_t max_buffer_size = WTPI_MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && in_buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + // take key handle, transform to session id + if (key_handle_length < sizeof(OEMCrypto_SESSION)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCrypto_SESSION session; + memcpy(&session, key_handle, sizeof(session)); + OEMCryptoSession* session_context = NULL; OEMCryptoEntitledKeySession* key_session = NULL; OEMCryptoResult result = @@ -2093,24 +2220,6 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( result = OPKI_CheckStatePreCall(session_context, API_GENERICENCRYPT); if (result != OEMCrypto_SUCCESS) return result; - RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); - RETURN_INVALID_CONTEXT_IF_NULL(out_buffer); - RETURN_INVALID_CONTEXT_IF_ZERO(buffer_length); - RETURN_INVALID_CONTEXT_IF_NULL(iv); - if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { - LOGE("Invalid algorithm."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length % AES_BLOCK_SIZE != 0) { - LOGE("buffer_length of %zu is not a multiple of the crypto block length.", - buffer_length); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - size_t max_buffer_size = WTPI_MaxBufferSizeForGenericCrypto(); - if (max_buffer_size != 0 && buffer_length > max_buffer_size) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } SymmetricKey* current_content_key = NULL; result = OPKI_GetCurrentContentKey(session_context, key_session, ¤t_content_key); @@ -2127,7 +2236,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( result = OPKI_UpdatePlaybackTimeAndUsageEntryStatus(session_context); if (result != OEMCrypto_SUCCESS) return result; result = WTPI_C1_AESCBCEncrypt(current_content_key->key_handle, in_buffer, - buffer_length, iv, out_buffer); + in_buffer_length, iv, out_buffer); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to AES CBC encrypt with result: %u", result); return result; @@ -2137,12 +2246,47 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( } OEMCryptoResult OEMCrypto_Generic_Decrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + + if (WTPI_ContentDecryptBypassesTA()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_handle); + RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); + RETURN_INVALID_CONTEXT_IF_NULL(out_buffer); + RETURN_INVALID_CONTEXT_IF_ZERO(in_buffer_length); + RETURN_INVALID_CONTEXT_IF_NULL(iv); + + if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { + LOGE("Invalid algorithm."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (in_buffer_length % AES_BLOCK_SIZE != 0) { + LOGE( + "in_buffer_length of %zu is not a multiple of the crypto block length.", + in_buffer_length); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + size_t max_buffer_size = WTPI_MaxBufferSizeForGenericCrypto(); + if (max_buffer_size != 0 && in_buffer_length > max_buffer_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + // take key handle, transform to session id + if (key_handle_length < sizeof(OEMCrypto_SESSION)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCrypto_SESSION session; + memcpy(&session, key_handle, sizeof(session)); + OEMCryptoSession* session_context = NULL; OEMCryptoEntitledKeySession* key_session = NULL; OEMCryptoResult result = @@ -2153,24 +2297,6 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( result = OPKI_CheckStatePreCall(session_context, API_GENERICDECRYPT); if (result != OEMCrypto_SUCCESS) return result; - RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); - RETURN_INVALID_CONTEXT_IF_NULL(out_buffer); - RETURN_INVALID_CONTEXT_IF_ZERO(buffer_length); - RETURN_INVALID_CONTEXT_IF_NULL(iv); - if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { - LOGE("Invalid algorithm."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length % AES_BLOCK_SIZE != 0) { - LOGE("buffer_length of %zu is not a multiple of the crypto block length.", - buffer_length); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - size_t max_buffer_size = WTPI_MaxBufferSizeForGenericCrypto(); - if (max_buffer_size != 0 && buffer_length > max_buffer_size) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } SymmetricKey* current_content_key = NULL; result = OPKI_GetCurrentContentKey(session_context, key_session, ¤t_content_key); @@ -2191,7 +2317,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( if (result != OEMCrypto_SUCCESS) return result; result = WTPI_C1_AESCBCDecrypt(current_content_key->key_handle, (size_t)key_size, - in_buffer, buffer_length, iv, out_buffer); + in_buffer, in_buffer_length, iv, out_buffer); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to AES CBC decrypt with result: %u", result); return result; @@ -2200,16 +2326,45 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( return OPKI_SetStatePostCall(session_context, API_GENERICDECRYPT); } -OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, - const uint8_t* in_buffer, +OEMCryptoResult OEMCrypto_Generic_Sign(const uint8_t* key_handle, + size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, OEMCrypto_Algorithm algorithm, - uint8_t* signature, + OEMCrypto_SharedMemory* signature, size_t* signature_length) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + + if (WTPI_ContentDecryptBypassesTA()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_handle); + RETURN_INVALID_CONTEXT_IF_NULL(signature_length); + + if (*signature_length < SHA256_DIGEST_LENGTH) { + *signature_length = SHA256_DIGEST_LENGTH; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + RETURN_INVALID_CONTEXT_IF_NULL(buffer); + RETURN_INVALID_CONTEXT_IF_ZERO(buffer_length); + RETURN_INVALID_CONTEXT_IF_NULL(signature); + + if (algorithm != OEMCrypto_HMAC_SHA256) { + LOGE("Invalid algorithm."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // take key handle, transform to session id + if (key_handle_length < sizeof(OEMCrypto_SESSION)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCrypto_SESSION session; + memcpy(&session, key_handle, sizeof(session)); + OEMCryptoSession* session_context = NULL; OEMCryptoEntitledKeySession* key_session = NULL; OEMCryptoResult result = @@ -2220,21 +2375,6 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, result = OPKI_CheckStatePreCall(session_context, API_GENERICSIGN); if (result != OEMCrypto_SUCCESS) return result; - RETURN_INVALID_CONTEXT_IF_NULL(signature_length); - - if (*signature_length < SHA256_DIGEST_LENGTH) { - *signature_length = SHA256_DIGEST_LENGTH; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); - RETURN_INVALID_CONTEXT_IF_ZERO(buffer_length); - RETURN_INVALID_CONTEXT_IF_NULL(signature); - if (algorithm != OEMCrypto_HMAC_SHA256) { - LOGE("Invalid algorithm."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - *signature_length = SHA256_DIGEST_LENGTH; size_t max_buffer_size = WTPI_MaxBufferSizeForGenericCrypto(); @@ -2257,7 +2397,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, if (result != OEMCrypto_SUCCESS) return result; result = OPKI_UpdatePlaybackTimeAndUsageEntryStatus(session_context); if (result != OEMCrypto_SUCCESS) return result; - result = WTPI_C1_HMAC_SHA256(current_content_key->key_handle, in_buffer, + result = WTPI_C1_HMAC_SHA256(current_content_key->key_handle, buffer, buffer_length, signature); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to HMAC-SHA256 with result: %u", result); @@ -2267,29 +2407,24 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, return OPKI_SetStatePostCall(session_context, API_GENERICSIGN); } -OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length) { +OEMCryptoResult OEMCrypto_Generic_Verify( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + size_t signature_length) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - OEMCryptoSession* session_context = NULL; - OEMCryptoEntitledKeySession* key_session = NULL; - OEMCryptoResult result = - GetSessionContext(session, &session_context, &key_session); - if (result != OEMCrypto_SUCCESS) return result; - ABORT_IF(session_context == NULL, - "GetSessionContext() provided invalid output."); - result = OPKI_CheckStatePreCall(session_context, API_GENERICVERIFY); - if (result != OEMCrypto_SUCCESS) return result; - RETURN_INVALID_CONTEXT_IF_NULL(in_buffer); + if (WTPI_ContentDecryptBypassesTA()) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_handle); + RETURN_INVALID_CONTEXT_IF_NULL(buffer); RETURN_INVALID_CONTEXT_IF_ZERO(buffer_length); RETURN_INVALID_CONTEXT_IF_NULL(signature); + if (signature_length != SHA256_DIGEST_LENGTH) { LOGE("signature_length is not the length of a SHA256 digest"); return OEMCrypto_ERROR_SIGNATURE_FAILURE; @@ -2303,6 +2438,24 @@ OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, if (max_buffer_size != 0 && buffer_length > max_buffer_size) { return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } + + // take key handle, transform to session id + if (key_handle_length < sizeof(OEMCrypto_SESSION)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCrypto_SESSION session; + memcpy(&session, key_handle, sizeof(session)); + + OEMCryptoSession* session_context = NULL; + OEMCryptoEntitledKeySession* key_session = NULL; + OEMCryptoResult result = + GetSessionContext(session, &session_context, &key_session); + if (result != OEMCrypto_SUCCESS) return result; + ABORT_IF(session_context == NULL, + "GetSessionContext() provided invalid output."); + result = OPKI_CheckStatePreCall(session_context, API_GENERICVERIFY); + if (result != OEMCrypto_SUCCESS) return result; + SymmetricKey* current_content_key = NULL; result = OPKI_GetCurrentContentKey(session_context, key_session, ¤t_content_key); @@ -2319,8 +2472,8 @@ OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, if (result != OEMCrypto_SUCCESS) return result; result = OPKI_UpdatePlaybackTimeAndUsageEntryStatus(session_context); if (result != OEMCrypto_SUCCESS) return result; - result = WTPI_C1_HMAC_SHA256_Verify(current_content_key->key_handle, - in_buffer, buffer_length, signature); + result = WTPI_C1_HMAC_SHA256_Verify(current_content_key->key_handle, buffer, + buffer_length, signature); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to HMAC-SHA256 verify with result: %u", result); return result; @@ -2337,9 +2490,9 @@ OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( // installation tool that uses a system key to unwrap the keybox and then // re-wraps it using a device key. This wrapped keybox can be stored on the // file system. I think we don't plan to use this. If we do, then Widevine - // needs to implement this function, and we have to agree on an porting layer - // interface for: - // decrypt w/system key -> encrypt w/device key -> return buffer. + // needs to implement this function, and we have to agree on an porting + // layer interface for: decrypt w/system key -> encrypt w/device key -> + // return buffer. // return OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -2371,8 +2524,10 @@ OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { } else if (provisioning_method == OEMCrypto_Keybox) { return WTPI_ValidateKeybox(); } else if (provisioning_method == OEMCrypto_BootCertificateChain) { - // Provisioning 4 does not use keybox or OEM cert as root. - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + // Although provisioning 4 does not use keybox as root, a keybox can still + // be present as a backup of root of trust, which can be validated as + // well. + return WTPI_ValidateKeybox(); } else { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -2409,6 +2564,10 @@ OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data, return WTPI_GetKeyDataFromKeybox(key_data, *key_data_length); } +OEMCryptoResult OEMCrypto_EnterTestMode(void) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, size_t length) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); @@ -2480,14 +2639,125 @@ uint32_t OEMCrypto_MinorAPIVersion(void) { return API_MINOR_VERSION; } OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length) { RETURN_INVALID_CONTEXT_IF_NULL(buffer_length); - const size_t max_length = strnlen(BUILD_INFO(), 128); - if (*buffer_length < max_length) { - *buffer_length = max_length; + if (buffer == NULL && *buffer_length > 0) + return OEMCrypto_ERROR_INVALID_CONTEXT; + + // First half of build info + static const char kBuildInfo1[] = + "{" + "\"soc_vendor\":\"" XSTR(OPK_CONFIG_SOC_VENDOR_NAME) "\"," + "\"soc_model\":\"" XSTR(OPK_CONFIG_SOC_MODEL_NAME) "\"," + "\"ta_ver\":\"" XSTR(API_MAJOR_VERSION) "." + XSTR(API_MINOR_VERSION) "." + XSTR(OPK_PATCH_VERSION) + OPK_IS_DEBUG_STR "+" __DATE__ __TIME__ "\"," + "\"uses_opk\":true," + "\"tee_os\":\"" XSTR(OPK_CONFIG_TEE_OS_NAME) "\"," + "\"tee_os_ver\":\"" XSTR(OPK_CONFIG_TEE_OS_VERSION) "\"," + "\"form_factor\":\"" XSTR(OPK_CONFIG_DEVICE_FORM_FACTOR) "\"," + "\"implementer\":\"" XSTR(OPK_CONFIG_IMPLEMENTER_NAME) "\"," + "\"fused\":"; + + // Add fused state + bool is_fused = false; + OEMCryptoResult res = WTPI_GetDeviceFusedStatus(&is_fused); + if (res != OEMCrypto_SUCCESS) return res; + static const char kFusedTrue[] = "true"; + static const char kFusedFalse[] = "false"; + const char* fused_state = is_fused ? kFusedTrue : kFusedFalse; + + // Rest of build info + static const char kBuildInfo2[] = +#if OPK_IS_DEBUG + "," + "\"opk_config\":" + "{" + "\"OPK_CONFIG_SECURITY_LEVEL\":\"" + XSTR(OPK_CONFIG_SECURITY_LEVEL) "\"," + "\"OPK_CONFIG_PROVISIONING_METHOD\":\"" + XSTR(OPK_CONFIG_PROVISIONING_METHOD)"\"," + "\"OPK_CONFIG_RESOURCE_RATING_TIER\":\"" + XSTR(OPK_CONFIG_RESOURCE_RATING_TIER)"\"," + "\"OPK_CONFIG_TA_ANTIROLLBACK_SUPPORTED\":\"" + XSTR(OPK_CONFIG_TA_ANTIROLLBACK_SUPPORTED)"\"," + "\"OPK_CONFIG_HW_ANTIROLLBACK_SUPPORTED\":\"" + XSTR(OPK_CONFIG_HW_ANTIROLLBACK_SUPPORTED)"\"," + "\"OPK_CONFIG_IS_CLOSED_PLATFORM\":\"" + XSTR(OPK_CONFIG_IS_CLOSED_PLATFORM)"\"," + "\"OPK_CONFIG_WATERMARKING_SUPPORT\":\"" + XSTR(OPK_CONFIG_WATERMARKING_SUPPORT)"\"," + "\"OPK_CONFIG_SUPPORTS_CGMSA\":\"" + XSTR(OPK_CONFIG_SUPPORTS_CGMSA)"\"," + "\"OPK_CONFIG_HAS_ANALOG_DISPLAY\":\"" + XSTR(OPK_CONFIG_HAS_ANALOG_DISPLAY)"\"," + "\"OPK_CONFIG_CAN_DISABLE_ANALOG_DISPLAY\":\"" + XSTR(OPK_CONFIG_CAN_DISABLE_ANALOG_DISPLAY)"\"," + "\"OPK_CONFIG_MAX_HDCP_CAPABILITY\":\"" + XSTR(OPK_CONFIG_MAX_HDCP_CAPABILITY)"\"," + "\"OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT\":\"" + XSTR(OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT)"\"," + "\"OPK_CONFIG_MAX_OUTPUT_SIZE_FOR_DECRYPT\":\"" + XSTR(OPK_CONFIG_MAX_OUTPUT_SIZE_FOR_DECRYPT)"\"," + "\"OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO\":\"" + XSTR(OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO)"\"," + "\"OPK_CONFIG_MAX_SAMPLE_SIZE\":\"" + XSTR(OPK_CONFIG_MAX_SAMPLE_SIZE)"\"," + "\"OPK_CONFIG_SUPPORTED_CERTIFICATES\":\"" + XSTR(OPK_CONFIG_SUPPORTED_CERTIFICATES)"\"," + "\"OPK_CONFIG_DECRYPT_BYPASSES_TA\":\"" + XSTR(OPK_CONFIG_DECRYPT_BYPASSES_TA)"\"," + "\"MAX_NUMBER_OF_SESSIONS\":\"" + XSTR(MAX_NUMBER_OF_SESSIONS)"\"," + "\"MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS\":\"" + XSTR(MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS)"\"," + "\"MAX_NUMBER_OF_KEYS\":\"" + XSTR(MAX_NUMBER_OF_KEYS)"\"," + "\"CONTENT_KEYS_PER_SESSION\":\"" + XSTR(CONTENT_KEYS_PER_SESSION)"\"," + "\"ENTITLEMENT_KEYS_PER_SESSION\":\"" + XSTR(ENTITLEMENT_KEYS_PER_SESSION)"\"," + "\"MAX_NUMBER_OF_USAGE_ENTRIES\":\"" + XSTR(MAX_NUMBER_OF_USAGE_ENTRIES)"\"," + "\"MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES\":\"" + XSTR(MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES)"\"," + "\"MAX_NUMBER_OF_ASYMMETRIC_KEYS\":\"" + XSTR(MAX_NUMBER_OF_ASYMMETRIC_KEYS)"\"," + "\"MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES\":\"" + XSTR(MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES)"\"," + "\"WRAPPED_MAC_KEY_SIZE\":\"" + XSTR(WRAPPED_MAC_KEY_SIZE)"\"," + "\"ENCRYPT_AND_SIGN_EXTRA\":\"" + XSTR(ENCRYPT_AND_SIGN_EXTRA)"\"," + "\"MAX_SYMMETRIC_KEY_SIZE\":\"" + XSTR(MAX_SYMMETRIC_KEY_SIZE)"\"," + "\"MAX_WRAPPED_SYMMETRIC_KEY_SIZE\":\"" + XSTR(MAX_WRAPPED_SYMMETRIC_KEY_SIZE)"\"," + "\"MAX_WRAPPED_ASYMMETRIC_KEY_SIZE\":\"" + XSTR(MAX_WRAPPED_ASYMMETRIC_KEY_SIZE)"\"," + "\"MAX_BCC_RESP_PAYLOAD_SIZE\":\"" + XSTR(MAX_BCC_RESP_PAYLOAD_SIZE)"\"," + "\"MAX_ASYMMETRIC_SIGNATURE_SIZE\":\"" + XSTR(MAX_ASYMMETRIC_SIGNATURE_SIZE)"\"" + "}" +#endif + "}"; + + const size_t build_info_length1 = strlen(kBuildInfo1); + const size_t fused_state_length = strlen(fused_state); + const size_t build_info_length2 = strlen(kBuildInfo2); + const size_t total_length = + build_info_length1 + build_info_length2 + fused_state_length; + if (*buffer_length < total_length) { + *buffer_length = total_length; return OEMCrypto_ERROR_SHORT_BUFFER; } - RETURN_INVALID_CONTEXT_IF_NULL(buffer); - *buffer_length = max_length; - memcpy(buffer, BUILD_INFO(), *buffer_length); + + *buffer_length = total_length; + memcpy(buffer, kBuildInfo1, build_info_length1); + memcpy(buffer + build_info_length1, fused_state, fused_state_length); + memcpy(buffer + build_info_length1 + fused_state_length, kBuildInfo2, + build_info_length2); + return OEMCrypto_SUCCESS; } @@ -2617,17 +2887,17 @@ OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(OEMCrypto_SESSION session, result); return result; } - size_t private_key_size; - result = WTPI_GetSignatureSize(private_key_handle, &private_key_size); + size_t signature_size; + result = WTPI_GetSignatureSize(private_key_handle, &signature_size); WTPI_FreeAsymmetricKeyHandle(private_key_handle); if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to get DRM private key size with result: %u", result); + LOGE("Failed to get DRM key signature size with result: %u", result); return result; } - result = OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key, - wrapped_drm_key_length, private_key_size, - allowed_schemes); + result = + OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key, + wrapped_drm_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to load DRM key"); goto cleanup; @@ -2717,7 +2987,8 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( } } else { LOGE( - "Invalid session state or padding scheme. session state: %#x, padding " + "Invalid session state or padding scheme. session state: %#x, " + "padding " "scheme: %u", session_context->state, padding_scheme); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -2762,16 +3033,10 @@ OEMCryptoResult OEMCrypto_LoadProvisioning( RETURN_INVALID_CONTEXT_IF_NULL(wrapped_private_key_length); uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; - size_t device_id_length = ODK_DEVICE_ID_LEN_MAX; - result = GetDeviceID(device_id, &device_id_length); - if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to get device id with result: %u", result); - return result; - } ODK_ParsedProvisioning parsed_response; result = ODK_ParseProvisioning(message, message_length, core_message_length, &session_context->nonce_values, device_id, - device_id_length, &parsed_response); + ODK_DEVICE_ID_LEN_MAX, &parsed_response); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to parse provisioning with result: %u", result); return result; @@ -2841,8 +3106,8 @@ OEMCryptoResult OEMCrypto_CreateUsageTableHeader(uint8_t* header_buffer, LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // OPKI_CreateUsageTableHeader handles validation of the parameters, so we do - // not validate them here. + // OPKI_CreateUsageTableHeader handles validation of the parameters, so we + // do not validate them here. return OPKI_CreateUsageTableHeader(header_buffer, header_buffer_length); } @@ -2879,8 +3144,8 @@ OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, result = OPKI_CheckStatePreCall(session_context, API_CREATENEWUSAGEENTRY); if (result != OEMCrypto_SUCCESS) return result; - // OPKI_CreateNewUsageEntry handles validation of the parameters, so we do not - // validate them here. + // OPKI_CreateNewUsageEntry handles validation of the parameters, so we do + // not validate them here. result = OPKI_CreateNewUsageEntry(session_context->session_id, usage_entry_number); if (result != OEMCrypto_SUCCESS) { @@ -3064,7 +3329,8 @@ OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, result = OPKI_MoveEntry(session_context->session_id, new_index); if (result != OEMCrypto_SUCCESS) { LOGE( - "Failed to move entry with result: %u, session_id = %u, new_index = %u", + "Failed to move entry with result: %u, session_id = %u, new_index = " + "%u", result, session_context->session_id, new_index); return result; } @@ -3078,8 +3344,8 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count, LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // OPKI_ShrinkUsageTableHeader handles validation of the parameters, so we do - // not validate them here. + // OPKI_ShrinkUsageTableHeader handles validation of the parameters, so we + // do not validate them here. return OPKI_ShrinkUsageTableHeader(new_entry_count, header_buffer, header_buffer_length); } @@ -3234,7 +3500,13 @@ OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( OEMCryptoEntitledKeySession* key_session_context = NULL; OEMCryptoResult result = GetSessionContext(key_session, &session_context, &key_session_context); - if (result != OEMCrypto_SUCCESS) return result; + if (result != OEMCrypto_SUCCESS) { + // In case that the entitlement session is closed prior to the entitled key + // session, the result of OPKI_GetSession() will not be OEMCrypto_SUCCESS, + // and that's ok. This entitled key session should already be released when + // its entitlement session was closed. Just return success here. + return OEMCrypto_SUCCESS; + } ABORT_IF(session_context == NULL, "Failed to get the entitlement session context."); ABORT_IF(key_session_context == NULL, @@ -3307,8 +3579,17 @@ OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( OPKI_CheckStatePreCall(session_context, API_GENERATECERTIFICATEKEYPAIR); if (result != OEMCrypto_SUCCESS) return result; - // Generate the key pair and fill the key type. - const size_t required_signature_size = 1024; + /* Generate the key pair and fill the key type. */ + size_t required_signature_size = MAX_ASYMMETRIC_SIGNATURE_SIZE; + if (session_context->prov40_oem_private_key == NULL) { + /* This is for obtaining an OEM leaf cert. The signature is a COSE_SIGN1 + * format. Adjust the required signature size. */ + result = WTPI_GetMaxBccKeyCoseSign1Size(&required_signature_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max COSE_SIGN1 size: %u", result); + return result; + } + } AsymmetricKeyType generated_key_type; result = WTPI_GenerateRandomCertificateKeyPair( &generated_key_type, wrapped_private_key, wrapped_private_key_size, @@ -3330,67 +3611,170 @@ OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( LOGE("Invalid key_type: %d", generated_key_type); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - - // The provisioning stage is determined by whether the prov40_oem_private_key - // is installed. NOT installed: first stage; Installed: second stage. + /* The provisioning stage is determined by whether the + * prov40_oem_private_key is installed. NOT installed: first stage; + * Installed: second stage. */ if (session_context->prov40_oem_private_key == NULL) { - // This is for obtaining an OEM leaf cert. Sign with BCC leaf private key. - result = WTPI_DeviceKeyCoseSign1(public_key, *public_key_size, - public_key_signature, - public_key_signature_size); - if (result != OEMCrypto_SUCCESS) return result; - return OPKI_SetStatePostCall(session_context, - API_GENERATECERTIFICATEKEYPAIR); - } - - // This is the second stage for obtaining a DRM cert. Sign with the installed - // prov40_oem_private_key. - WTPI_AsymmetricKey_Handle signing_key_handle; - uint32_t allowed_schemes_unused; - AsymmetricKey* oem_private_key = session_context->prov40_oem_private_key; - result = WTPI_UnwrapIntoAsymmetricKeyHandle( - oem_private_key->wrapped_key, oem_private_key->wrapped_key_length, - oem_private_key->key_type, &signing_key_handle, &allowed_schemes_unused); - if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to unwrap OEM private key into key handle with result: %u", - result); - return result; - } - - // Sign the generated public key. - switch (oem_private_key->key_type) { - case DRM_ECC_PRIVATE_KEY: { - result = WTPI_ECCSign(signing_key_handle, public_key, *public_key_size, - public_key_signature, public_key_signature_size); - break; + /* This is the first stage for obtaining an OEM leaf cert. Sign with BCC + * leaf private key. */ + result = + WTPI_BccKeyCoseSign1(public_key, *public_key_size, public_key_signature, + public_key_signature_size); + } else { + /* This is the second stage for obtaining a DRM cert. Sign with the + * installed prov40_oem_private_key. */ + WTPI_AsymmetricKey_Handle signing_key_handle; + uint32_t allowed_schemes_unused; + AsymmetricKey* oem_private_key = session_context->prov40_oem_private_key; + result = WTPI_UnwrapIntoAsymmetricKeyHandle( + oem_private_key->wrapped_key, oem_private_key->wrapped_key_length, + oem_private_key->key_type, &signing_key_handle, + &allowed_schemes_unused); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to unwrap OEM private key into key handle with result: %u", + result); + return result; } - case DRM_RSA_PRIVATE_KEY: { - // If the signing key is RSA, the signing key must be OEM private key. - if ((session_context->prov40_oem_allowed_schemes & kSign_RSASSA_PSS) != - kSign_RSASSA_PSS) { - LOGE("Bad prov40 OEM RSA padding scheme: %x", - session_context->prov40_oem_allowed_schemes); - result = OEMCrypto_ERROR_INVALID_KEY; + /* Sign the generated public key. */ + switch (oem_private_key->key_type) { + case DRM_ECC_PRIVATE_KEY: { + result = WTPI_ECCSign(signing_key_handle, public_key, *public_key_size, + public_key_signature, public_key_signature_size); break; } - result = WTPI_RSASign(signing_key_handle, public_key, *public_key_size, - public_key_signature, public_key_signature_size, - kSign_RSASSA_PSS); - break; + case DRM_RSA_PRIVATE_KEY: { + /* If the signing key is RSA, the signing key must be OEM private key. + */ + if ((session_context->prov40_oem_allowed_schemes & kSign_RSASSA_PSS) != + kSign_RSASSA_PSS) { + LOGE("Bad prov40 OEM RSA padding scheme: %x", + session_context->prov40_oem_allowed_schemes); + result = OEMCrypto_ERROR_INVALID_KEY; + break; + } + result = WTPI_RSASign(signing_key_handle, public_key, *public_key_size, + public_key_signature, public_key_signature_size, + kSign_RSASSA_PSS); + break; + } + case PROV40_ED25519_PRIVATE_KEY: + default: + LOGE("Unexpected signing private key type"); + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + break; } - case PROV40_ED25519_PRIVATE_KEY: - default: - LOGE("Unexpected signing private key type"); - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - break; + WTPI_FreeAsymmetricKeyHandle(signing_key_handle); } - WTPI_FreeAsymmetricKeyHandle(signing_key_handle); if (result != OEMCrypto_SUCCESS) { return result; } + /* Store the generated key for signing the provisioning request. */ + WTPI_AsymmetricKey_Handle csr_signing_key_handle; + uint32_t allowed_schemes; + result = WTPI_UnwrapIntoAsymmetricKeyHandle( + wrapped_private_key, *wrapped_private_key_size, generated_key_type, + &csr_signing_key_handle, &allowed_schemes); + if (result != OEMCrypto_SUCCESS) { + LOGE( + "Failed to unwrap the CSR signing key into key handle with result: " + "%u", + result); + return result; + } + size_t signature_size; + result = WTPI_GetSignatureSize(csr_signing_key_handle, &signature_size); + WTPI_FreeAsymmetricKeyHandle(csr_signing_key_handle); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get signature size with result: %u", result); + return result; + } + if (session_context->prov40_csr_signing_key != NULL) { + /* Free any existing keys. Although this shouldn't happen, log an error + * and continue. */ + LOGE("Provisioning 4.0 request signing key should have been released"); + result = OPKI_FreeAsymmetricKeyFromTable( + &session_context->prov40_csr_signing_key); + if (result != OEMCrypto_SUCCESS) return result; + } + result = OPKI_CreateAsymmetricKey(&session_context->prov40_csr_signing_key, + generated_key_type, wrapped_private_key, + *wrapped_private_key_size, signature_size, + allowed_schemes); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to create asymmetric CSR signing key with result: %u", result); + return result; + } return OPKI_SetStatePostCall(session_context, API_GENERATECERTIFICATEKEYPAIR); } +OEMCryptoResult OEMCrypto_GetDeviceInformation(uint8_t* device_info, + size_t* device_info_length) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Bypass the check below for factory build which needs to call + // OEMCrypto_GetDeviceInformation() when Prov 2.0 is still enabled +#ifndef FACTORY_BUILD_ONLY + if (WTPI_GetProvisioningMethod() != OEMCrypto_BootCertificateChain) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } +#endif + RETURN_INVALID_CONTEXT_IF_NULL(device_info_length); + + OEMCryptoResult result = OEMCrypto_SUCCESS; + size_t max_device_info_size = WTPI_MaxDeviceInfoSize(); + if (device_info == NULL || *device_info_length < max_device_info_size) { + *device_info_length = max_device_info_size; + result = OEMCrypto_ERROR_SHORT_BUFFER; + } + if (result != OEMCrypto_SUCCESS) return result; + *device_info_length = max_device_info_size; + return WTPI_GetDeviceInformation(device_info, device_info_length); +} + +OEMCryptoResult OEMCrypto_GetDeviceSignedCsrPayload( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + uint8_t* signed_csr_payload, size_t* signed_csr_payload_length) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Bypass the check below for factory build which needs to call + // OEMCrypto_GetDeviceSignedCsrPayload() when Prov 2.0 is still enabled +#ifndef FACTORY_BUILD_ONLY + + if (WTPI_GetProvisioningMethod() != OEMCrypto_BootCertificateChain) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } +#endif + RETURN_INVALID_CONTEXT_IF_NULL(challenge); + RETURN_INVALID_CONTEXT_IF_ZERO(challenge_length); + RETURN_INVALID_CONTEXT_IF_NULL(encoded_device_info); + RETURN_INVALID_CONTEXT_IF_ZERO(encoded_device_info_length); + RETURN_INVALID_CONTEXT_IF_NULL(signed_csr_payload_length); + static const size_t kMaxChallengeSize = 64; + if (challenge_length > kMaxChallengeSize) { + LOGE("Invalid challenge size: %zu", challenge_length); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + size_t max_cose_sign1_size; + OEMCryptoResult result = WTPI_GetMaxBccKeyCoseSign1Size(&max_cose_sign1_size); + if (result != OEMCrypto_SUCCESS) return result; + if (signed_csr_payload == NULL || + *signed_csr_payload_length < max_cose_sign1_size) { + *signed_csr_payload_length = max_cose_sign1_size; + result = OEMCrypto_ERROR_SHORT_BUFFER; + } + if (result != OEMCrypto_SUCCESS) return result; + *signed_csr_payload_length = max_cose_sign1_size; + return WTPI_GetSignedCsrPayload( + challenge, challenge_length, encoded_device_info, + encoded_device_info_length, signed_csr_payload, + signed_csr_payload_length); +} + OEMCryptoResult OEMCrypto_InstallOemPrivateKey( OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { @@ -3430,17 +3814,17 @@ OEMCryptoResult OEMCrypto_InstallOemPrivateKey( result); return result; } - size_t private_key_size; - result = WTPI_GetSignatureSize(private_key_handle, &private_key_size); + size_t signature_size; + result = WTPI_GetSignatureSize(private_key_handle, &signature_size); WTPI_FreeAsymmetricKeyHandle(private_key_handle); if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to get DRM private key size with result: %u", result); + LOGE("Failed to get OEM key signature size with result: %u", result); return result; } result = OPKI_LoadProv40OEMKey( session_context, oem_key_type, wrapped_private_key, - wrapped_private_key_length, private_key_size, allowed_schemes); + wrapped_private_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to install OEM key"); goto cleanup; @@ -3520,7 +3904,8 @@ OEMCryptoResult OEMCrypto_ProductionReady(void) { #else LOGD( "OPK was not built in debug mode. This message should never be logged, " - "therefore. If you are reading this message, something has gone wrong."); + "therefore. If you are reading this message, something has gone " + "wrong."); #endif const bool wtpi_prod_ready = WTPI_IsProductionReady(); @@ -3601,3 +3986,31 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void) { } return WTPI_GetWatermarkingSupport(); } + +OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm( + OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + RETURN_INVALID_CONTEXT_IF_NULL(algorithm); + if (OPKI_GetSessionType(session) != SESSION_TYPE_OEMCRYPTO) { + LOGE("Unexpected session type."); + return OEMCrypto_ERROR_INVALID_SESSION; + } + OEMCryptoSession* session_context = NULL; + OEMCryptoResult result = OPKI_GetSession(session, &session_context); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get session with result: %u, session ID = %u", result, + session); + return result; + } + ABORT_IF_NULL(session_context); + return OPKI_GetSessionSignatureHashAlgorithm(session_context, algorithm); +} + +OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session UNUSED, + uint8_t* key_token UNUSED, + size_t* key_token_length UNUSED) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index 829a969..02a74e1 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -11,9 +11,9 @@ // values that are conventionally defined to indicate debug/non-debug. #if !defined(OPK_IS_DEBUG) # if !defined(NDEBUG) && defined(_DEBUG) -# define OPK_IS_DEBUG true +# define OPK_IS_DEBUG 1 # else -# define OPK_IS_DEBUG false +# define OPK_IS_DEBUG 0 # endif #endif @@ -23,6 +23,9 @@ # define OPK_IS_DEBUG_STR "" #endif +#define XSTR(s) STR(s) +#define STR(s) #s + // For the OPK version, mirror the major.minor values of the supported OEMCrypto // API. Increment the patch value to distinguish between different releases of // OPK for a single major.minor pair. For example, the first release of OPK @@ -30,8 +33,8 @@ // OEMCrypto API version would be v17.0.1; once the supported OEMCrypto API // version bumps to v17.1, the first released OPK implementation would be // v17.1.0 -#define API_MAJOR_VERSION 17 -#define API_MINOR_VERSION 0 -#define OPK_PATCH_VERSION 2 +#define API_MAJOR_VERSION 18 +#define API_MINOR_VERSION 1 +#define OPK_PATCH_VERSION 0 #endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.c index c7d831d..4bd729b 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.c @@ -37,9 +37,12 @@ OEMCryptoResult OPKI_NumberOfUsedAsymmetricKeys(uint32_t* num_used_keys) { return OEMCrypto_SUCCESS; } -OEMCryptoResult OPKI_CreateAsymmetricKey( - AsymmetricKey** key, AsymmetricKeyType key_type, const uint8_t* wrapped_key, - size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes) { +OEMCryptoResult OPKI_CreateAsymmetricKey(AsymmetricKey** key, + AsymmetricKeyType key_type, + const uint8_t* wrapped_key, + size_t wrapped_key_length, + size_t signature_size, + uint32_t allowed_schemes) { if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0) return OEMCrypto_ERROR_INVALID_CONTEXT; OEMCryptoResult result; @@ -64,7 +67,7 @@ OEMCryptoResult OPKI_CreateAsymmetricKey( cur_key = OPKI_AllocFromObjectTable(&key_table, NULL); if (cur_key == NULL) return OEMCrypto_ERROR_TOO_MANY_KEYS; result = OPKI_InitializeAsymmetricKey(cur_key, key_type, wrapped_key, - wrapped_key_length, key_size, + wrapped_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { OPKI_FreeAsymmetricKeyFromTable(key); diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.h index b9223ef..514edee 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.h @@ -27,7 +27,7 @@ OEMCryptoResult OPKI_NumberOfUsedAsymmetricKeys(uint32_t* num_used_keys); not be NULL. */ OEMCryptoResult OPKI_CreateAsymmetricKey( AsymmetricKey** key, AsymmetricKeyType key_type, const uint8_t* wrapped_key, - size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes); + size_t wrapped_key_length, size_t signature_size, uint32_t allowed_schemes); /* Given a pointer to a AsymmetricKey*, attempts to free the AsymmetricKey it points to if it exists, and then sets the pointer to the AsymmetricKey to diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_build_info.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_build_info.h deleted file mode 100644 index 8205c48..0000000 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_build_info.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary - source code may only be used and distributed under the Widevine - License Agreement. */ - -#ifndef OEMCRYPTO_TA_OEMCRYPTO_BUILD_INFO_H_ -#define OEMCRYPTO_TA_OEMCRYPTO_BUILD_INFO_H_ - -#include "oemcrypto_api_macros.h" - -#define XSTR(s) STR(s) -#define STR(s) #s - -// WTPI_BUILD_INFO should be a string provided at compile time with any desired -// platform-specific information -#if !defined(WTPI_BUILD_INFO) -# error("WTPI_BUILD_INFO not defined") -#endif - -#define BUILD_INFO() \ - "Widevine OPK v" XSTR(API_MAJOR_VERSION) "." XSTR( \ - API_MINOR_VERSION) "." XSTR(OPK_PATCH_VERSION) OPK_IS_DEBUG_STR \ - " " WTPI_BUILD_INFO - -#endif /* OEMCRYPTO_TA_OEMCRYPTO_BUILD_INFO_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c index 2b8304d..cdf109f 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c @@ -22,9 +22,12 @@ OEMCryptoResult OPKI_InitializeSymmetricKey(SymmetricKey* key, return OEMCrypto_SUCCESS; } -OEMCryptoResult OPKI_InitializeAsymmetricKey( - AsymmetricKey* key, AsymmetricKeyType key_type, const uint8_t* wrapped_key, - size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes) { +OEMCryptoResult OPKI_InitializeAsymmetricKey(AsymmetricKey* key, + AsymmetricKeyType key_type, + const uint8_t* wrapped_key, + size_t wrapped_key_length, + size_t signature_size, + uint32_t allowed_schemes) { if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0) { return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -34,7 +37,7 @@ OEMCryptoResult OPKI_InitializeAsymmetricKey( key->key_type = key_type; memcpy(key->wrapped_key, wrapped_key, wrapped_key_length); key->wrapped_key_length = wrapped_key_length; - key->key_size = key_size; + key->signature_size = signature_size; key->allowed_schemes = allowed_schemes; return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h index 57d3d67..f303fcc 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h @@ -7,7 +7,7 @@ #include "oemcrypto_key_control_block.h" #include "oemcrypto_key_types.h" -#include "wtpi_config_macros.h" +#include "opk_config.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -32,11 +32,7 @@ typedef struct AsymmetricKey { uint8_t wrapped_key[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE]; size_t wrapped_key_length; uint32_t ref_count; - /* This is the actual size of the asymmetric key in bytes when being loaded. - It is a shortcut to getting the key size without unwrapping the key first. - It is useful in cases where only the key size is needed but not the key - content. */ - size_t key_size; + size_t signature_size; uint32_t allowed_schemes; } AsymmetricKey; @@ -54,7 +50,7 @@ OEMCryptoResult OPKI_InitializeSymmetricKey(SymmetricKey* key, Caller retains ownership of all pointers and they must not be NULL. */ OEMCryptoResult OPKI_InitializeAsymmetricKey( AsymmetricKey* key, AsymmetricKeyType key_type, const uint8_t* wrapped_key, - size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes); + size_t wrapped_key_length, size_t signature_size, uint32_t allowed_schemes); /* Frees the key handle associated with this key if it exists and then clears the key. Returns the result of freeing the key handle. diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_control_block.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_control_block.c index 1c7257e..ae83ae4 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_control_block.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_control_block.c @@ -31,7 +31,8 @@ OEMCryptoResult OPKI_ParseKeyControlBlock(const uint8_t* kcb, key_control_block.control_bits = extract_field_from_KCB(kcb, 3); const char* verification = key_control_block.verification; - if (memcmp(verification, "kc17", 4) && /* add in version 17 api */ + if (memcmp(verification, "kc18", 4) && /* add in version 18 api */ + memcmp(verification, "kc17", 4) && /* add in version 17 api */ memcmp(verification, "kc16", 4) && /* add in version 16 api */ memcmp(verification, "kc15", 4) && /* add in version 15 api */ memcmp(verification, "kc14", 4) && /* add in version 14 api */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c index 623a36a..cdedc97 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c @@ -42,6 +42,8 @@ OEMCryptoResult OPK_ParseDestBufferDesc( return OEMCrypto_SUCCESS; case OEMCrypto_BufferType_Direct: return OEMCrypto_ERROR_NOT_IMPLEMENTED; + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; } return OEMCrypto_ERROR_INVALID_CONTEXT; diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c index 84545fa..e42f276 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c @@ -20,7 +20,7 @@ size_t OPKI_SignedHeaderSize(int table_size UNUSED) { return sizeof(SignedSavedUsageHeader); } -size_t OPKI_SignedEntrySize() { return sizeof(SignedSavedUsageEntry); } +size_t OPKI_SignedEntrySize(void) { return sizeof(SignedSavedUsageEntry); } OEMCryptoResult OPKI_PackSignedUsageHeader( uint8_t* buffer, size_t buffer_size, const SignedSavedUsageHeader* header) { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.h index fcd5367..f606d7e 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.h @@ -9,7 +9,7 @@ #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_key_types.h" -#include "wtpi_config_macros.h" +#include "opk_config.h" /* File types. */ #define USAGE_TABLE_HEADER 0x68656164 diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c index 19b5d10..36828a4 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c @@ -4,6 +4,7 @@ #include "oemcrypto_session.h" +#include #include #include "odk.h" @@ -63,12 +64,20 @@ OEMCryptoResult OPKI_InitializeSession(OEMCryptoSession* session, OEMCryptoResult OPKI_TerminateSession(OEMCryptoSession* session) { if (session == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; - OEMCryptoResult result = OEMCrypto_SUCCESS; - - result = OPKI_FreeAsymmetricKeyFromTable(&session->drm_private_key); OEMCryptoResult free_key_result = - OPKI_FreeKeyFromTable(&session->mac_key_client); + OPKI_FreeAsymmetricKeyFromTable(&session->drm_private_key); + OEMCryptoResult result = free_key_result; + + free_key_result = + OPKI_FreeAsymmetricKeyFromTable(&session->prov40_oem_private_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + free_key_result = + OPKI_FreeAsymmetricKeyFromTable(&session->prov40_csr_signing_key); + if (result == OEMCrypto_SUCCESS) result = free_key_result; + + free_key_result = OPKI_FreeKeyFromTable(&session->mac_key_client); if (result == OEMCrypto_SUCCESS) result = free_key_result; free_key_result = OPKI_FreeKeyFromTable(&session->mac_key_server); @@ -109,6 +118,7 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, case API_GENERATENONCE: switch (session->state) { case (SESSION_OPENED): + case (SESSION_INSTALL_OEM_PRIVATE_KEY): case (SESSION_LOAD_DRM_RSA_KEY): return OEMCrypto_SUCCESS; default: @@ -143,6 +153,8 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, } case API_PREPANDSIGN_PROVISION_REQUEST: switch (session->state) { + case (SESSION_OPENED): + case (SESSION_INSTALL_OEM_PRIVATE_KEY): case (SESSION_PREPARING_REQUEST): case (SESSION_LOAD_OEM_RSA_KEY): return OEMCrypto_SUCCESS; @@ -180,6 +192,8 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, case (SESSION_OPENED): case (SESSION_PREPARING_REQUEST): case (SESSION_USAGE_ENTRY_LOADED): + // Provisioning 4 skips LoadProvisioning + case (SESSION_WAIT_FOR_PROVISIONING): // This can happen when using testing the CDM with a pre-provisioned // device. case (SESSION_LOAD_DRM_RSA_KEY): @@ -192,6 +206,8 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, case (SESSION_OPENED): case (SESSION_PREPARING_REQUEST): case (SESSION_USAGE_ENTRY_LOADED): + // Provisioning 4 skips LoadProvisioning + case (SESSION_WAIT_FOR_PROVISIONING): return OEMCrypto_SUCCESS; default: goto err; @@ -253,6 +269,7 @@ OEMCryptoResult OPKI_CheckStatePreCall(OEMCryptoSession* session, goto err; } case API_SELECTKEY: + case API_GETKEYHANDLE: case API_LOADENTITLEDCONTENTKEYS: case API_QUERYKEYCONTROL: switch (session->state) { @@ -392,6 +409,7 @@ OEMCryptoResult OPKI_SetStatePostCall(OEMCryptoSession* session, case API_REUSEUSAGEENTRY: case API_LOADENTITLEDCONTENTKEYS: case API_SELECTKEY: + case API_GETKEYHANDLE: case API_QUERYKEYCONTROL: case API_MOVEENTRY: case API_REPORTUSAGE: @@ -421,7 +439,8 @@ OEMCryptoResult OPKI_SetNonce(OEMCryptoSession* session, uint32_t nonce) { OEMCryptoResult OPKI_LoadDRMKey(OEMCryptoSession* session, AsymmetricKeyType key_type, const uint8_t* wrapped_key, - size_t wrapped_key_length, size_t key_size, + size_t wrapped_key_length, + size_t signature_size, uint32_t allowed_schemes) { if (session == NULL || wrapped_key == NULL || wrapped_key_length == 0 || !IsSupportedDrmKeyType(key_type)) { @@ -437,9 +456,9 @@ OEMCryptoResult OPKI_LoadDRMKey(OEMCryptoSession* session, allowed_schemes = 0; } - result = - OPKI_CreateAsymmetricKey(&session->drm_private_key, key_type, wrapped_key, - wrapped_key_length, key_size, allowed_schemes); + result = OPKI_CreateAsymmetricKey(&session->drm_private_key, key_type, + wrapped_key, wrapped_key_length, + signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to create asymmetric DRM private key with result: %u", result); return result; @@ -456,7 +475,7 @@ OEMCryptoResult OPKI_LoadProv40OEMKey(OEMCryptoSession* session, AsymmetricKeyType key_type, const uint8_t* wrapped_key, size_t wrapped_key_length, - size_t key_size, + size_t signature_size, uint32_t allowed_schemes) { if (session == NULL || wrapped_key == NULL || wrapped_key_length == 0 || !IsSupportedDrmKeyType(key_type)) { @@ -473,8 +492,8 @@ OEMCryptoResult OPKI_LoadProv40OEMKey(OEMCryptoSession* session, } result = OPKI_CreateAsymmetricKey(&session->prov40_oem_private_key, key_type, - wrapped_key, wrapped_key_length, key_size, - allowed_schemes); + wrapped_key, wrapped_key_length, + signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to create asymmetric OEM private key with result: %u", result); return result; @@ -505,7 +524,7 @@ NO_IGNORE_RESULT static OEMCryptoResult DeriveKey( return result; } -NO_IGNORE_RESULT OEMCryptoResult OPKI_DeriveMacAndEncryptionKeys( +OEMCryptoResult OPKI_DeriveMacAndEncryptionKeys( OEMCryptoSession* session, WTPI_K1_SymmetricKey_Handle master_key, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, size_t enc_key_context_length) { @@ -578,10 +597,10 @@ OEMCryptoResult OPKI_GenerateSignatureWithMacKeyClient( return OEMCrypto_SUCCESS; } -NO_IGNORE_RESULT static bool DRMKeyMaySign(const OEMCryptoSession* session) { - switch (session->drm_private_key->key_type) { +NO_IGNORE_RESULT static bool DRMKeyMaySign(const AsymmetricKey* key) { + switch (key->key_type) { case DRM_RSA_PRIVATE_KEY: - return (session->allowed_schemes & kSign_RSASSA_PSS) == kSign_RSASSA_PSS; + return (key->allowed_schemes & kSign_RSASSA_PSS) == kSign_RSASSA_PSS; case DRM_ECC_PRIVATE_KEY: return true; case PROV40_ED25519_PRIVATE_KEY: @@ -601,42 +620,81 @@ OEMCryptoResult OPKI_GenerateCertSignature(OEMCryptoSession* session, signature == NULL || signature_length == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - switch (signature_type) { - case CERT_SIGNATURE_OEM: - // TODO(b/225216277): implement this. - // return SignMessageWithOEMPrivateKey(message, message_length, signature, - // signature_length); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - case CERT_SIGNATURE_DRM: { - if (!DRMKeyMaySign(session)) return OEMCrypto_ERROR_INVALID_KEY; - WTPI_AsymmetricKey_Handle drm_private_key_handle; - uint32_t allowed_schemes; - AsymmetricKey* drm_private_key = session->drm_private_key; - OEMCryptoResult result = WTPI_UnwrapIntoAsymmetricKeyHandle( - drm_private_key->wrapped_key, drm_private_key->wrapped_key_length, - drm_private_key->key_type, &drm_private_key_handle, &allowed_schemes); - if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to unwrap DRM private key into key handle with result: %u", - result); - return result; - } - if (drm_private_key->key_type == DRM_RSA_PRIVATE_KEY) { - result = WTPI_RSASign(drm_private_key_handle, message, message_length, - signature, signature_length, kSign_RSASSA_PSS); - } else { - result = WTPI_ECCSign(drm_private_key_handle, message, message_length, - signature, signature_length); - } - WTPI_FreeAsymmetricKeyHandle(drm_private_key_handle); - return result; - } - default: - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (signature_type == CERT_SIGNATURE_OEM) { + // TODO(b/225216277): implement this. + // return SignMessageWithOEMPrivateKey(message, message_length, signature, + // signature_length); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; } + + AsymmetricKey* signing_key; + if (signature_type == CERT_SIGNATURE_DRM) { + if (!DRMKeyMaySign(session->drm_private_key)) + return OEMCrypto_ERROR_INVALID_KEY; + signing_key = session->drm_private_key; + } else if (signature_type == CERT_SIGNATURE_CSR) { + if (!DRMKeyMaySign(session->prov40_csr_signing_key)) + return OEMCrypto_ERROR_INVALID_KEY; + signing_key = session->prov40_csr_signing_key; + } else { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + WTPI_AsymmetricKey_Handle signing_key_handle; + uint32_t allowed_schemes; + OEMCryptoResult result = WTPI_UnwrapIntoAsymmetricKeyHandle( + signing_key->wrapped_key, signing_key->wrapped_key_length, + signing_key->key_type, &signing_key_handle, &allowed_schemes); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to unwrap signing key into key handle with result: %u", + result); + return result; + } + if (signing_key->key_type == DRM_RSA_PRIVATE_KEY) { + result = WTPI_RSASign(signing_key_handle, message, message_length, + signature, signature_length, kSign_RSASSA_PSS); + } else { + result = WTPI_ECCSign(signing_key_handle, message, message_length, + signature, signature_length); + } + WTPI_FreeAsymmetricKeyHandle(signing_key_handle); + return result; +} + +NO_IGNORE_RESULT OEMCryptoResult OPKI_GetSessionSignatureHashAlgorithm( + OEMCryptoSession* session, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + + const AsymmetricKey* key; + if (session->drm_private_key != NULL) { + key = session->drm_private_key; + } else if (session->prov40_oem_private_key != NULL) { + key = session->prov40_oem_private_key; + } else if (session->prov40_csr_signing_key != NULL) { + key = session->prov40_csr_signing_key; + } else { + LOGE("No asymmetric keys loaded."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + WTPI_AsymmetricKey_Handle key_handle; + uint32_t ignored; + OEMCryptoResult result = WTPI_UnwrapIntoAsymmetricKeyHandle( + key->wrapped_key, key->wrapped_key_length, key->key_type, &key_handle, + &ignored); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to unwrap key into key handle with result: %u", result); + return result; + } + result = + WTPI_GetSignatureHashAlgorithm(key_handle, key->key_type, hash_algorithm); + WTPI_FreeAsymmetricKeyHandle(key_handle); + return result; } NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOnline( - OEMCryptoSession* session, uint32_t nonce, uint32_t control) { + OEMCryptoSession* session, uint32_t nonce, uint32_t control UNUSED) { if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; if (session->nonce_values.nonce != nonce) { return OEMCrypto_ERROR_INVALID_NONCE; @@ -654,7 +712,7 @@ NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOnline( } NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOffline( - OEMCryptoSession* session, uint32_t nonce, uint32_t control) { + OEMCryptoSession* session, uint32_t nonce, uint32_t control UNUSED) { if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; switch (OPKI_GetUsageEntryStatus(session->session_id)) { default: /* Invalid status. */ @@ -712,6 +770,7 @@ OEMCryptoResult OPKI_InstallKey(OEMCryptoSession* session, SymmetricKey** current_key_ptr; uint32_t current_key_index = 0; SymmetricKeyType key_type; + uint8_t minimum_patch_level = 0; if (session->license_type == OEMCrypto_ContentLicense) { if (key_data_length != KEY_SIZE_128 && key_data_length != KEY_SIZE_256) { /* Generic crypto allows both key sizes. */ @@ -814,9 +873,9 @@ OEMCryptoResult OPKI_InstallKey(OEMCryptoSession* session, result = OEMCrypto_ERROR_UNKNOWN_FAILURE; goto cleanup; } - uint8_t minimum_patch_level = (current_key->key_control_block.control_bits & - CONTROL_SECURITY_PATCH_LEVEL_MASK) >> - CONTROL_SECURITY_PATCH_LEVEL_SHIFT; + minimum_patch_level = (current_key->key_control_block.control_bits & + CONTROL_SECURITY_PATCH_LEVEL_MASK) >> + CONTROL_SECURITY_PATCH_LEVEL_SHIFT; if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) { LOGE( "Security patch level doesn't meet the minimum requirement. Current: " @@ -1053,6 +1112,77 @@ OEMCryptoResult OPKI_GetKeyControlBlock( return OEMCrypto_SUCCESS; } +static bool PrioritizeHdcpLevel(OEMCrypto_HDCP_Capability level, + uint8_t* priority) { + // Since OEMCrypto_HDCP_Capability is no longer sorted, we need to convert all + // values to a sorted priority so we can efficiently compare them. + // + // If new enum values are added to OEMCrypto_HDCP_Capability, we'll have to + // add them to this function. Since OEMCrypto_HDCP_Capability is no longer + // sorted, we cannot assume we know how to handle new values. + if (level == HDCP_NONE || level == HDCP_V1 || + level == HDCP_NO_DIGITAL_OUTPUT) { + *priority = (uint8_t)level; + return true; + } else if (level >= HDCP_V2 && level <= HDCP_V2_3) { + *priority = (uint8_t)level + 5; + return true; + } else if (level >= HDCP_V1_0 && level <= HDCP_V1_4) { + *priority = (uint8_t)level - 4; + return true; + } else { + return false; + } +} + +static bool IsHdcpLevelSufficient(OEMCrypto_HDCP_Capability required, + OEMCrypto_HDCP_Capability current) { + uint8_t required_priority = 0; + if (!PrioritizeHdcpLevel(required, &required_priority)) { + LOGE("Unrecognized HDCP requirement %u", required); + return false; + } + uint8_t current_priority = 0; + if (!PrioritizeHdcpLevel(current, ¤t_priority)) { + LOGE("Unrecognized current HDCP level %u", current); + return false; + } + + return current_priority >= required_priority; +} + +OEMCryptoResult OPKI_EnforceOutputRestrictions(KeyControlBlock control) { + const OEMCrypto_HDCP_Capability capability = WTPI_CurrentHDCPCapability(); + if (capability != HDCP_NO_DIGITAL_OUTPUT && + (control.control_bits & CONTROL_HDCP_REQUIRED)) { + /* Check to see if HDCP requirements are satisfied. */ + const uint8_t required_hdcp = + (control.control_bits & CONTROL_HDCP_VERSION_MASK) >> + CONTROL_HDCP_VERSION_SHIFT; + if (!IsHdcpLevelSufficient(required_hdcp, capability) || + capability == HDCP_NONE) { + return OEMCrypto_ERROR_INSUFFICIENT_HDCP; + } + } + /* Disable the analog outputs, if required. */ + if (control.control_bits & CONTROL_DISABLE_ANALOG_OUTPUT) { + if (WTPI_IsAnalogDisplayActive() && !WTPI_DisableAnalogDisplay()) { + LOGE("Analog output could not be disabled"); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + /* If CGMS-A is required, either it must be active or analog output must be + disabled. */ + if (control.control_bits & CONTROL_CGMS_MASK) { + if (!WTPI_IsCGMS_AActive() && WTPI_IsAnalogDisplayActive() && + !WTPI_DisableAnalogDisplay()) { + LOGE("CGMS must be active if analog output is active"); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + return OEMCrypto_SUCCESS; +} + OEMCryptoResult OPKI_CheckCurrentContentKeyUsage( OEMCryptoSession* session, OEMCryptoEntitledKeySession* key_session, uint32_t use_type, OPK_OutputBuffer_Type buffer_type) { @@ -1089,34 +1219,7 @@ OEMCryptoResult OPKI_CheckCurrentContentKeyUsage( return OEMCrypto_ERROR_DECRYPT_FAILED; } } - const OEMCrypto_HDCP_Capability capability = WTPI_CurrentHDCPCapability(); - if (capability != HDCP_NO_DIGITAL_OUTPUT && - (control.control_bits & CONTROL_HDCP_REQUIRED)) { - /* Check to see if HDCP requirements are satisfied. */ - const uint8_t required_hdcp = - (control.control_bits & CONTROL_HDCP_VERSION_MASK) >> - CONTROL_HDCP_VERSION_SHIFT; - if (required_hdcp > capability || capability == HDCP_NONE) { - return OEMCrypto_ERROR_INSUFFICIENT_HDCP; - } - } - /* Disable the analog outputs, if required. */ - if (control.control_bits & CONTROL_DISABLE_ANALOG_OUTPUT) { - if (WTPI_IsAnalogDisplayActive() && !WTPI_DisableAnalogDisplay()) { - LOGE("Analog output could not be disabled"); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } - /* If CGMS-A is required, either it must be active or analog output must be - disabled. */ - if (control.control_bits & CONTROL_CGMS_MASK) { - if (!WTPI_IsCGMS_AActive() && WTPI_IsAnalogDisplayActive() && - !WTPI_DisableAnalogDisplay()) { - LOGE("CGMS must be active if analog output is active"); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } - return OEMCrypto_SUCCESS; + return OPKI_EnforceOutputRestrictions(control); } OEMCryptoResult OPKI_UpdatePlaybackTimeAndUsageEntryStatus( diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h index 7f243a6..a180c7e 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h @@ -71,11 +71,13 @@ typedef enum OEMCryptoSessionAPI { API_CREATEENTITLEDKEYSESSION = (int)0x6d7d9bfc, API_INSTALLOEMPRIVATEKEY = (int)0xd6195c63, API_GENERATECERTIFICATEKEYPAIR = (int)0x30871a8a, + API_GETKEYHANDLE = (int)0x81aac42f, } OEMCryptoSessionAPI; typedef enum CertSignatureType { CERT_SIGNATURE_OEM = (int)0x386eebf3, CERT_SIGNATURE_DRM = (int)0x6b4684e3, + CERT_SIGNATURE_CSR = (int)0x1f37a40a, } CertSignatureType; typedef struct OEMCryptoSession { @@ -85,6 +87,10 @@ typedef struct OEMCryptoSession { /* This key can only be used to sign the generated cert key in * provisioning 4.*/ AsymmetricKey* prov40_oem_private_key; + /* This key can only be used to sign the provisioning 4 requests. For stage 1, + * it is the generated OEM private key. For stage 2, it is the generated DRM + * private key. */ + AsymmetricKey* prov40_csr_signing_key; SymmetricKey* mac_key_server; SymmetricKey* mac_key_client; SymmetricKey* encryption_key; @@ -165,7 +171,7 @@ NO_IGNORE_RESULT OEMCryptoResult OPKI_LoadDRMKey(OEMCryptoSession* session, AsymmetricKeyType key_type, const uint8_t* wrapped_key, size_t wrapped_key_length, - size_t key_size, + size_t signature_size, uint32_t allowed_schemes); /* Attempts to load the wrapped OEM private key |wrapped_key| into |session|'s @@ -175,7 +181,7 @@ NO_IGNORE_RESULT OEMCryptoResult OPKI_LoadDRMKey(OEMCryptoSession* session, NO_IGNORE_RESULT OEMCryptoResult OPKI_LoadProv40OEMKey(OEMCryptoSession* session, AsymmetricKeyType key_type, const uint8_t* wrapped_key, size_t wrapped_key_length, - size_t key_size, uint32_t allowed_schemes); + size_t signature_size, uint32_t allowed_schemes); /* Derives mac and encryption keys from the specific key. Uses AES-128-CMAC and |mac_ and enc_key_contexts| to derive and create a mac_key_server, @@ -225,6 +231,12 @@ NO_IGNORE_RESULT OEMCryptoResult OPKI_GenerateCertSignature( uint8_t* signature, size_t* signature_length, CertSignatureType signature_type); +/* Gets the type of hashing algorithm that will be used during RSASSA-PSS or + EDSA if the currently loaded asymmetric key were used for signing. */ +NO_IGNORE_RESULT OEMCryptoResult OPKI_GetSessionSignatureHashAlgorithm( + OEMCryptoSession* session, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm); + /* Installs the key using the given data into the |session| depending on the license_type. Decrypts the |key_data| using the encryption_key in the session and then uses the first 128 bits of the decrypted key to decrypt @@ -305,9 +317,19 @@ NO_IGNORE_RESULT OEMCryptoResult OPKI_GetKeyControlBlock( SymmetricKey* content_key, OEMCryptoSession* session, OEMCryptoEntitledKeySession* key_session, KeyControlBlock* control_block); -/* Checks whether the current content key selected in the |session|, or the - current entitled content key selected in the |key_session| can be used - in the operation given by |use_type| and with the given |buffer_type|. +/* Checks the output protections required by the given key control block and + enforces them if possible. Returns OEMCrypto_ERROR_INSUFFICIENT_HDCP if the + HDCP requirements are not met, OEMCrypto_ERROR_ANALOG_OUTPUT if the analog + display requirements are not met, and OEMCrypto_SUCCESS if all protections + were applied or are already being met. */ +NO_IGNORE_RESULT OEMCryptoResult +OPKI_EnforceOutputRestrictions(KeyControlBlock control); + +/* Checks whether the current key (either the content key selected in the + |session| or the entitled content key selected in the |key_session|) can be + used in the operation given by |use_type| and with the given |buffer_type|, + including whether the output protections required by the key can be enforced. + (e.g. This function is a superset of OPKI_EnforceOutputRestrictions().) Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there is no valid current content key, OEMCrypto_ERROR_INVALID_CONTEXT if |use_type| is not allowed by the key control block or if the replay mask is set in the key control block, or diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c index d1535c0..8ac0c2e 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c @@ -4,32 +4,9 @@ #include "oemcrypto_session_key_table.h" -#include - #include "odk_util.h" #include "wtpi_abort_interface.h" -NO_IGNORE_RESULT static SymmetricKey** get_key_table( - OEMCryptoSession* session, OEMCrypto_LicenseType license_type, - uint32_t* num_keys) { - if (session == NULL || num_keys == NULL) { - return NULL; - } - - switch (license_type) { - case OEMCrypto_ContentLicense: - *num_keys = session->num_content_keys; - return session->content_keys; - case OEMCrypto_EntitlementLicense: - *num_keys = session->num_entitlement_keys; - return session->entitlement_keys; - } - - // Execution can only reach this point if license_type was not a valid member - // of the enumeration. - return NULL; -} - SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session, bool is_content_key, const uint8_t* key_id, size_t key_id_length) { @@ -41,16 +18,20 @@ SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session, LOGE("Cannot get entitlement key for content license"); return NULL; } - uint32_t num_keys; - OEMCrypto_LicenseType license_type = - is_content_key ? OEMCrypto_ContentLicense : OEMCrypto_EntitlementLicense; - SymmetricKey** key_table = get_key_table(session, license_type, &num_keys); - for (size_t i = 0; i < num_keys; i++) { - SymmetricKey* key = key_table[i]; - ABORT_IF(key == NULL, "Key at index %zu is NULL", i); - if (key_id_length == key->key_id_size && - crypto_memcmp(key->key_id, key_id, key_id_length) == 0) { - return key; + SymmetricKey** keys = NULL; + uint32_t num_keys = 0; + if (is_content_key) { + keys = session->content_keys; + num_keys = session->num_content_keys; + } else { + keys = session->entitlement_keys; + num_keys = session->num_entitlement_keys; + } + for (uint32_t i = 0; i < num_keys; i++) { + ABORT_IF(keys[i] == NULL, "Key at index %u is NULL", i); + if (key_id_length == keys[i]->key_id_size && + crypto_memcmp(keys[i]->key_id, key_id, key_id_length) == 0) { + return keys[i]; } } return NULL; diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp b/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp index f6f8c22..2f8432b 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp @@ -4,8 +4,6 @@ { 'variables': { - # Include directory that contains wtpi_config_macros.h. - 'config_macros_header_dir%': 'wtpi_reference', 'wtpi_build_info%': 'unspecified_platform', }, 'includes': [ @@ -16,7 +14,8 @@ '.', '../../include', 'wtpi', - '<(config_macros_header_dir)', + 'wtpi_reference', + '<(opk_config_dir)', ], 'sources': [ 'oemcrypto.c', @@ -45,7 +44,7 @@ '.', '../../include', 'wtpi', - '<(config_macros_header_dir)', + '<(opk_config_dir)', ], }, }, @@ -54,17 +53,11 @@ 'target_name': 'oemcrypto_ta', 'type': 'static_library', 'standalone_static_library': 1, - 'defines': [ - 'WTPI_BUILD_INFO="<(wtpi_build_info)"', - ], }, { 'target_name': 'oemcrypto_ta_linux_tee', 'type': 'static_library', 'standalone_static_library': 1, - 'defines': [ - 'WTPI_BUILD_INFO="Linux_TEE_Simulator"', - ], }, ], } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c index 136a1bf..075cce5 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c @@ -11,10 +11,10 @@ #include "odk_endian.h" #include "odk_util.h" #include "oemcrypto_check_macros.h" +#include "oemcrypto_compiler_detection.h" #include "oemcrypto_object_table.h" #include "oemcrypto_serialized_usage_table.h" #include "wtpi_clock_interface_layer1.h" -#include "wtpi_config_macros.h" #include "wtpi_device_key_interface.h" #include "wtpi_generation_number_interface.h" #include "wtpi_logging_interface.h" @@ -82,6 +82,17 @@ static UsageTableState g_usage_table_state = USAGE_TABLE_NOT_INITIALIZED; * valid if |g_usage_table_state| is USAGE_TABLE_ACTIVE. */ static UsageTable g_usage_table; +#if __has_attribute(packed) || COMPATIBLE_WITH_GCC(3) || \ + COMPATIBLE_WITH_CLANG(3) +# define PACKED __attribute__((packed)) +#elif defined(_WIN32) +# define PACKED +# pragma pack(push) +# pragma pack(1) +#else +# define PACKED +#endif + /* TODO(b/158720996): figure out a way to avoid __attribute__(packed). */ typedef struct { uint8_t signature[20]; // -- HMAC SHA1 of the rest of the report. @@ -93,7 +104,11 @@ typedef struct { int64_t seconds_since_first_decrypt; // now - time_of_first_decrypt int64_t seconds_since_last_decrypt; // now - time_of_last_decrypt uint8_t pst[]; -} __attribute__((packed)) OEMCrypto_PST_Report; +} PACKED OEMCrypto_PST_Report; + +#if defined(_WIN32) +# pragma pack(pop) +#endif static void ClearTable(void) { g_usage_table.table_size = 0; @@ -438,6 +453,8 @@ NO_IGNORE_RESULT static OEMCryptoResult RollGenerationNumber( return OEMCrypto_ERROR_SYSTEM_INVALIDATED; } g_usage_table.master_generation_number = new_generation_number; + g_counter_info.master_generation_number = + g_usage_table.master_generation_number; entry->data.generation_number++; g_usage_table.generation_numbers[entry->data.index] = entry->data.generation_number; @@ -503,8 +520,7 @@ GetUsageEntryStatusFromEntry(UsageEntry* entry) { return USAGE_ENTRY_NEW; } -NO_IGNORE_RESULT UsageEntryStatus -OPKI_GetUsageEntryStatus(OEMCrypto_SESSION session_id) { +UsageEntryStatus OPKI_GetUsageEntryStatus(OEMCrypto_SESSION session_id) { UsageEntry* entry = FindUsageEntry(session_id); if (!entry) return USAGE_ENTRY_NONE; return GetUsageEntryStatusFromEntry(entry); @@ -558,6 +574,8 @@ OEMCryptoResult OPKI_CreateUsageTableHeader(uint8_t* header_buffer, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } g_usage_table_state = USAGE_TABLE_ACTIVE_STATE; + g_counter_info.master_generation_number = + g_usage_table.master_generation_number; return EncryptAndSignHeader(header_buffer, *header_buffer_length); } @@ -911,8 +929,7 @@ OEMCryptoResult OPKI_VerfiyUsageEntryPST(OEMCrypto_SESSION session_id, } OEMCryptoResult OPKI_SetUsageEntryMacKeys( - const OEMCrypto_SESSION session_id, - WTPI_K1_SymmetricKey_Handle mac_key_server, + OEMCrypto_SESSION session_id, WTPI_K1_SymmetricKey_Handle mac_key_server, WTPI_K1_SymmetricKey_Handle mac_key_client) { if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.h index 41fc939..8d9a8c0 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.h @@ -21,6 +21,8 @@ typedef enum UsageEntryStatus { USAGE_ENTRY_DEACTIVATED = (int)0xdacba37, } UsageEntryStatus; +extern ODK_MessageCounterInfo g_counter_info; + /** * Clear out memory for the usage table. No other usage table functions may be * called before this. */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_config_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_config_interface.h index 8536376..7a1d416 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_config_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_config_interface.h @@ -6,7 +6,6 @@ #define OEMCRYPTO_TA_WTPI_CONFIG_INTERFACE_H_ #include "OEMCryptoCENC.h" -#include "wtpi_config_macros.h" #ifdef __cplusplus extern "C" { @@ -203,6 +202,23 @@ size_t WTPI_MaxSampleSize(void); */ uint32_t WTPI_SupportedCertificates(void); +/** + * Indicates whether the TA expects to be used for content decryption, or if the + * REE will use dedicated hardware to decrypt content (effectively bypassing the + * TA). + * + * A return value of true means that OEMCrypto_GetKeyHandle will return + * a wrapped key that can be passed around the REE. The key wrapping mechanism + * is known only to the TA and the decryption hardware. DecryptCENC and + * Generic_* functions will not be expected to be implemented in the TEE. + * + * A return value of false means that the TEE will expect to execute DecryptCENC + * and all Generic_* functions. GetKeyHandle() will return a fake key handle, + * which is the session ID as a 4-byte buffer. + * + */ +bool WTPI_ContentDecryptBypassesTA(void); + /// @} #ifdef __cplusplus diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h index d1ec19f..57d48d2 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h @@ -138,6 +138,8 @@ OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle, * hash function and places the result in |out_buffer|. |key_handle| is a handle * to the key used in the derivation. |out_buffer| must be >= 20 bytes. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for the crypto operation @@ -177,6 +179,8 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length, * the hash function and places the result in |out_buffer|. |key_handle| is a * handle to the key used in the derivation. |out_buffer| must be >= 32 bytes. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for HMAC operation @@ -198,6 +202,8 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle, * |signature| using SHA256 as the hash function. |key_handle| is a handle to * the key used in the derivation. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for HMAC operation @@ -465,7 +471,7 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( * Wraps the |key_handle| into a buffer that can be saved to the file system. * The wrapping key must be device unique, and is derived with the specified * |context|. Caller ensures that |wrapped_key_length| is equal to the wrapped - * key size specified in wtpi_config_macros.h. + * key size specified in opk_config.h * * Caller retains ownership of all parameters. * @@ -521,6 +527,32 @@ OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( */ OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle); +/** + * Converts a key handle to a byte buffer that will later be exported to + * a non-secure context. Since the destination is non-secure, the key material + * must be wrapped or otherwise obfuscated. + * + * If the TA is being used to decrypt all content, this function is not needed. + * This function is required for "bypass decrypt" only, where the REE only uses + * the TA to allocate and refresh content keys, while dedicated hardware is used + * to consume those keys (that were exported by this function) and decrypt + * content. + * + * @param[in] key_handle: key handle to be exported + * @param[out] out_buffer: destination buffer + * @param[in,out] out_buffer_length: destination buffer length + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_CONTEXT null key handle or pointers + * @retval OEMCrypto_ERROR_SHORT_BUFFER out_buffer_length is too small for the + * key to be exported. out_buffer_length will be set to the required length. + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures + * + * Caller retains ownership of all parameters. + */ +OEMCryptoResult WTPI_K1_PrepareExternalKeyHandle( + WTPI_K1_SymmetricKey_Handle key_handle, uint8_t* out_buffer, + size_t* out_buffer_length); /// @} #ifdef __cplusplus diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h index e491a8f..64bd27e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h @@ -420,7 +420,7 @@ OEMCryptoResult WTPI_K2_DeriveKeyFromKeyHandle( * Wraps the |key_handle| into a buffer that can be saved to the file system. * The wrapping key must be device unique, and is derived with the specified * |context|. Caller ensures that |wrapped_key_length| is equal to the wrapped - * key size specified in wtpi_config_macros.h. + * key size specified in opk_config.h. * * Caller retains ownership of all parameters. * diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h index fe8b9ee..eedbae9 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h @@ -51,7 +51,7 @@ typedef struct tee_asymmetric_key_handle* WTPI_AsymmetricKey_Handle; * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL or * |input_length| is 0 * @retval OEMCrypto_ERROR_INVALID_KEY if |serialized_bytes| does not point - * to a valid private key of the specified |key_type| + * to a valid private key of the specified |key_type|. * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures/ * @retval OEMCrypto_SUCCESS otherwise */ @@ -156,6 +156,16 @@ OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, * the given |padding scheme| and place the result in |signature|. * |key| is a handle to the RSA key used for signing. * + * If |padding_scheme| is kSign_RSASSA_PSS, this function should hash the + * message with SHA-256, then sign the result with RSASSA-PSS, as outlined in + * the OEMCrypto Integration Guide section "RSASSA-PSS Details". If SHA-256 + * cannot be supported, SHA-1 may be used, but Widevine strongly prefers + * SHA-256. + * + * If |padding_scheme| is kSign_PKCS1_Block1, this function should pad the + * message with PKCS1 v1.5 block1, then perform a raw private key RSA operation + * on the result. + * * Caller retains ownership of all pointers. * * @param[in] key: handle with RSA key required to sign @@ -206,9 +216,14 @@ OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key, /** * Sign |message_length| bytes of |message| with the given ECC key handle using - * the ECDSA with a curve specific hashing algorithm and place the result in - * |signature|. |key| is a handle to the ECC key used for signing. The - * resulting signature must be ASN.1 encoded as specified in RFC 3279 2.2.3. + * the ECDSA with a curve-specific hashing algorithm and place the result in + * |signature|. |key| is a handle to the ECC key used for signing. + * + * The hashing algorithm is specified by the OEMCrypto Integration Guide section + * "ECDSA Details". The hashing algorithm used should be written to + * |hash_algorithm|. + * + * The resulting signature must be ASN.1 encoded as specified in RFC 3279 2.2.3. * * Caller retains ownership of all pointers. * @@ -281,87 +296,32 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, size_t* signature_length); /** - * Writes the boot certificate chain (BCC) in provisioning 4.0 to |out|, with - * number of bytes specified in |out_length|. + * Determine which SHA algorithm would be used if the given key were used in a + * signing operation. (e.g. WTPI_RSASign or WTPI_ECCSign) * - * Caller retains ownership of all pointers. + * For RSA keys, this should be the hash algorithm for RSASSA-PSS, not the mask + * algorithm, as outlined in the OEMCrypto Integration Guide section "RSASSA-PSS + * Details". This should be SHA-256. If SHA-256 cannot be supported, SHA-1 may + * be used, but Widevine strongly prefers SHA-256. * - * @param[out] out: output buffer to write BCC - * @param[in,out] out_length: size of bcc buffer, may be modified based on - * used/required space of output. + * For ECC keys, this should be the digest algorithm for ECDSA. The hashing + * algorithm depends on the key size and is specified by the OEMCrypto + * Integration Guide section "ECDSA Details". * - * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |out_length| is NULL - * @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_UNKNOWN_FAILURE any other failures + * For ED25519 keys, the hashing algorithm is always SHA-512. + * + * @param[in] key: input key handle + * @param[in] key_type: type of asymmetric key + * @param[out] hash_algorithm: the hashing algorithm that would be used for the + * given |key| + * + * @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_GetBootCertificateChain(uint8_t* out, size_t* out_length); - -/** - * Generate a pair of RSA or ECC key pair, which will be used in the certificate - * signing request as specified in provisioning 4. The output key type must be - * either RSA or ECC, which should be specified in |key_type|. - * - * |public_key| must be encoded as an X.509 SubjectPublicKeyInfo type. - * - * |wrapped_private_key| must be encoded as a PKCS#8 PrivateKeyInfo type and - * then wrapped with an implementation-specific method. The resulting wrapped - * private key will be used by WTPI_UnwrapIntoAsymmetricKeyHandle() for crypto - * operations. - * - * Returns - * OEMCrypto_ERROR_SHORT_BUFFER if |wrapped_private_key_length| or - * |public_key_length| is too small, or if |wrapped_private_key| or |public_key| - * is NULL, in which case the appropriate length should be returned. - * OEMCrypto_ERROR_INVALID_CONTEXT if |key_type|, |wrapped_private_key_length| - * or |public_key_length| is NULL. - * OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures. - * OEMCrypto_SUCCESS otherwise. - * - * Caller retains ownership of all pointers. - * - * @param[out] key_type: Type (RSA or EC) of the generated key pair. - * @param[out] wrapped_private_key: The generated private key, wrapped with - * encryption key for storage. - * @param[in,out] wrapped_private_key_length: size of |wrapped_private_key| - * buffer, may be modified based on used/required space of output. - * @param[out] public_key: The generated public key. - * @param[in,out] public_key_length: size of |public_key_length| buffer, may be - * modified based on used/required space of output. - */ -OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( - AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length, uint8_t* public_key, - size_t* public_key_length); - -/** - * Used the device specific asymmetric key pair as specified in provisioning 4 - * to sign |message| and write the COSE_SIGN1 format signature to |signature|. - * Note that the device key must be unique per individual device. The key must - * be identical across reboots. - * - * Caller retains ownership of all parameters. - * - * @param[in] message: input data to be signed - * @param[in] message_length: length of input data in bytes - * @param[out] signature: destination buffer for signature - * @param[in,out] signature_length: size of |signature| buffer, may be - * modified based on used/required space of output. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if - * |signature| is NULL, in which case it sets |signature_length| to the - * appropriate length. - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if |message_length| is too large. - * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |message_length| is 0 or if any of - * the pointers except |signature| are NULL. - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures. - */ -OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length); +OEMCryptoResult WTPI_GetSignatureHashAlgorithm( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm); /// @} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h new file mode 100644 index 0000000..a953c00 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h @@ -0,0 +1,229 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#ifndef OEMCRYPTO_TA_WTPI_PROVISIONING_4_INTERFACE_H_ +#define OEMCRYPTO_TA_WTPI_PROVISIONING_4_INTERFACE_H_ + +#include "OEMCryptoCENC.h" + +#include "wtpi_crypto_asymmetric_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup provisioning-4 Provisioning 4.0 + * + * This component includes functions relating to the Provisioning 4.0 model of + * device provisioning, such as BCC retrieval, ECC key derivation, CSR payload + * generation, and COSE_SIGN1 signing and population. + * + * If a device is not using provisioning 4.0, then these functions can return + * NOT_IMPLEMENTED. + * + * @{ + */ + +/** + * Writes the boot certificate chain (BCC) in provisioning 4.0 to |out|, with + * number of bytes specified in |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out: output buffer to write BCC + * @param[in,out] out_length: size of bcc buffer, may be modified based on + * used/required space of output. + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |out_length| is NULL + * @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_UNKNOWN_FAILURE any other failures + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length); + +/** + * Writes the maximum possible size of the boot certificate chain (BCC) in + * provisioning 4.0 to |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out_length: max size of the BCC + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length); + +/** + * Generate a pair of RSA or ECC key pair, which will be used in the certificate + * signing request as specified in provisioning 4. The output key type must be + * either RSA or ECC, which should be specified in |key_type|. + * + * |public_key| must be encoded as an X.509 SubjectPublicKeyInfo type. + * + * |wrapped_private_key| must be encoded as a PKCS#8 PrivateKeyInfo type and + * then wrapped with an implementation-specific method. The resulting wrapped + * private key will be used by WTPI_UnwrapIntoAsymmetricKeyHandle() for crypto + * operations. + * + * Returns + * OEMCrypto_ERROR_SHORT_BUFFER if |wrapped_private_key_length| or + * |public_key_length| is too small, or if |wrapped_private_key| or |public_key| + * is NULL, in which case the appropriate length should be returned. + * OEMCrypto_ERROR_INVALID_CONTEXT if |key_type|, |wrapped_private_key_length| + * or |public_key_length| is NULL. + * OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures. + * OEMCrypto_SUCCESS otherwise. + * + * Caller retains ownership of all pointers. + * + * @param[out] key_type: Type (RSA or EC) of the generated key pair. + * @param[out] wrapped_private_key: The generated private key, wrapped with + * encryption key for storage. + * @param[in,out] wrapped_private_key_length: size of |wrapped_private_key| + * buffer, may be modified based on used/required space of output. + * @param[out] public_key: The generated public key. + * @param[in,out] public_key_length: size of |public_key_length| buffer, may be + * modified based on used/required space of output. + */ +OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( + 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 + * COSE_Sign1 format to |signed_csr_payload|, with number of bytes specified in + * |signed_csr_payload_length|. The definition of the signed payload structure + * can be found here: + * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl + * The CSR payload is signed by the leaf cert of the Boot Certificate Chain + * (BCC). It is only used in the factory, uploaded along with the device + * information and validated during device registration. This function applies + * to Provisioning 4.0 devices only. + * + * Caller retains ownership of all pointers. + * + * @param[in] challenge: input buffer of challenge to be signed + * @param[in] challenge_length: size of challenge buffer + * @param[in] encoded_device_info: input buffer of device information to be + * signed + * @param[in] encoded_device_info_length: size of device information buffer + * @param[out] signed_csr_payload: output buffer to write signed Csr payload + * @param[in,out] signed_csr_payload_length: size of signed Csr payload buffer, + * may be modified based on used/required space of output. + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |challenge_length| or + * |encoded_device_info_length| is 0, or any pointer is NULL + * @retval OEMCrypto_ERROR_SHORT_BUFFER if |signed_csr_payload_length| is too + * small, or |signed_csr_payload| is NULL, in which case it sets + * |signed_csr_payload_length| and |signed_csr_payload_length| to the + * appropriate length + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4.0 is not supported + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetSignedCsrPayload(const uint8_t* challenge, + size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_length); + +/** + * Returns the max device information size for OEMCrypto_GetDeviceInformation. + */ +size_t WTPI_MaxDeviceInfoSize(void); + +/** + * Writes the serialized device information in CBOR map format to |out|, with + * number of bytes specified in |out_length|. The supported device properties + * are defined here: + * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl + * Widevine strongly recommends that the manufacturer, model, and fused fields + * be included. The fields manufacturer and model will be used to determine the + * system id of the device. The fused field will be used to determine if the + * device is a test only device. This function applies to Provisioning 4.0 + * devices only. + * + * Caller retains ownership of all pointers. + * + * @param[out] out: output buffer to write device information + * @param[in,out] out_length: size of device information buffer, may be modified + * based on used/required space of output. + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |out_length| is NULL + * @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_UNKNOWN_FAILURE any other failures + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4.0 is not supported, + * or device information is not available on the platform + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetDeviceInformation(uint8_t* out, size_t* out_length); + +/** + * Used the device specific asymmetric key pair as specified in provisioning 4 + * to sign |message| and write the COSE_SIGN1 format signature to |signature|. + * Note that the device key must be unique per individual device. The key must + * be identical across reboots. + * + * Caller retains ownership of all parameters. + * + * @param[in] message: input data to be signed + * @param[in] message_length: length of input data in bytes + * @param[out] signature: destination buffer for signature + * @param[in,out] signature_length: size of |signature| buffer, may be + * modified based on used/required space of output. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if + * |signature| is NULL, in which case it sets |signature_length| to the + * appropriate length. + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if |message_length| is too large. + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |message_length| is 0 or if any of + * the pointers except |signature| are NULL. + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures. + */ +OEMCryptoResult WTPI_BccKeyCoseSign1(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length); + +/** + * Writes the maximum possible size of the COSE_SIGN1 format signature generated + * by the device key to |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out_length: max size of the COSE_SIGN1 format signature + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetMaxBccKeyCoseSign1Size(size_t* out_length); + +/** + * Writes whether the device is fused, aka secure boot is enforced for the + * processor, to |is_fused|. + * + * Caller retains ownership of all pointers. + * + * @param[out] is_fused: whether or not the device is fused + * + * @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_GetDeviceFusedStatus(bool* is_fused); + +/// @} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h index 71fdfa1..d7d7078 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h @@ -51,12 +51,16 @@ OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input, size_t length); /** - * Attempt to validate the current keybox loaded. + * Attempt to validate the current keybox loaded. When provisioning 4.0 is + * enabled, this function can be also used to validate the backup keybox if + * the installation of a backup keybox is supported. * * @retval OEMCrypto_SUCCESS success * @retval OEMCrypto_ERROR_BAD_MAGIC if magic field is not "kbox" * @retval OEMCrypto_ERROR_BAD_CRC if computed CRC is not equivalent to stored * CRC + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4.0 is enabled and + * backup keybox is not supported */ OEMCryptoResult WTPI_ValidateKeybox(void); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/asymmetric_key.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/asymmetric_key.h new file mode 100644 index 0000000..1dd66de --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/asymmetric_key.h @@ -0,0 +1,22 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#ifndef OEMCRYPTO_TA_REF_ASYMMETRIC_KEY_H_ +#define OEMCRYPTO_TA_REF_ASYMMETRIC_KEY_H_ + +#include "ecc_util.h" +#include "oemcrypto_key_types.h" +#include "openssl/curve25519.h" +#include "openssl/evp.h" +#include "openssl/rsa.h" + +typedef struct tee_asymmetric_key_handle { + AsymmetricKeyType key_type; + RSA* rsa_key; + EC_KEY* ecc_key; + // Consider to use EVP_KEY instead of serialized key. + uint8_t ed25519_key[ED25519_PRIVATE_KEY_LEN]; +} tee_asymmetric_key_handle; + +#endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h new file mode 100644 index 0000000..8128b40 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h @@ -0,0 +1,395 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef WIDEVINE_OPK_CONFIG_DEFAULT_H_ +#define WIDEVINE_OPK_CONFIG_DEFAULT_H_ + +#include "OEMCryptoCENC.h" + +/// @addtogroup config +/// @{ + +/* + * OPK configuration header file defaults + * + * Copy/paste into your project, or define your own values and include this file + * for the rest. To allow compile time overrides, use #ifndef guards around your + * values as shown below. + * + */ + +#ifndef OPK_CONFIG_SOC_VENDOR +# define OPK_CONFIG_SOC_VENDOR "Reference" +#endif + +#ifndef OPK_CONFIG_SOC_CHIPSET +# define OPK_CONFIG_SOC_CHIPSET "Test only" +#endif + +/* + * + * Config values returned by wtpi_config_interface.h functions + * + */ + +/** + * Security level of the TA (L1, L3). + * + * Type is OEMCrypto_Security_Level + * + */ +#ifndef OPK_CONFIG_SECURITY_LEVEL +# define OPK_CONFIG_SECURITY_LEVEL OEMCrypto_Level1 +#endif + +/** + * Provisioning method used by the TA. + * + * Type is OEMCrypto_ProvisioningMethod + */ +#ifndef OPK_CONFIG_PROVISIONING_METHOD +# define OPK_CONFIG_PROVISIONING_METHOD OEMCrypto_Keybox +#endif + +/** + * Resource rating tier for the TA. + * + * Type is uint32_t. Value must be 1, 2, 3, or 4 + */ +#ifndef OPK_CONFIG_RESOURCE_RATING_TIER +# define OPK_CONFIG_RESOURCE_RATING_TIER 1 +#endif + +/** + * Whether anti-rollback protections for the TEE software are enabled. + * + * Type is OPK_FeatureStatus + */ +#ifndef OPK_CONFIG_TA_ANTIROLLBACK_SUPPORTED +# define OPK_CONFIG_TA_ANTIROLLBACK_SUPPORTED OPK_FEATURE_NOT_SUPPORTED +#endif + +/** + * Whether the device has hardware protection preventing rollback of the usage + * table. + * + * Type is bool + */ +#ifndef OPK_CONFIG_HW_ANTIROLLBACK_SUPPORTED +# define OPK_CONFIG_HW_ANTIROLLBACK_SUPPORTED false +#endif + +/** + * Whether the underlying platform is entirely protected from the user, and the + * decrypt pipeline can safely use clear output buffers. + * + * If there is a rich execution environment that is accessible by the user, that + * cannot be a closed platform. + * + * Type is bool + */ +#ifndef OPK_CONFIG_IS_CLOSED_PLATFORM +# define OPK_CONFIG_IS_CLOSED_PLATFORM false +#endif + +/** + * Supported watermarking features of the device. + * + * Type is OEMCrypto_WatermarkingSupport + */ +#ifndef OPK_CONFIG_WATERMARKING_SUPPORT +# define OPK_CONFIG_WATERMARKING_SUPPORT OEMCrypto_WatermarkingNotSupported +#endif + +/** + * Whether the device supports 2-bit CGMS-A + * + * Type is bool + */ +#ifndef OPK_CONFIG_SUPPORTS_CGMSA +# define OPK_CONFIG_SUPPORTS_CGMSA false +#endif + +/** + * Whether the device has an analog display. + * + * Type is bool + */ +#ifndef OPK_CONFIG_HAS_ANALOG_DISPLAY +# define OPK_CONFIG_HAS_ANALOG_DISPLAY false +#endif + +/** + * Whether the device is capable of disabling its analog display. + * + * Type is bool + */ +#ifndef OPK_CONFIG_CAN_DISABLE_ANALOG_DISPLAY +# define OPK_CONFIG_CAN_DISABLE_ANALOG_DISPLAY false +#endif + +/** + * Maximum HDCP capability of the device. + * + * Type is OEMCrypto_HDCP_Capability + */ +#ifndef OPK_CONFIG_MAX_HDCP_CAPABILITY +# define OPK_CONFIG_MAX_HDCP_CAPABILITY HDCP_NO_DIGITAL_OUTPUT +#endif + +/** + * Maximum buffer size for DecryptCENC input in bytes. + * + * 0 means no limit. + * + * Type is size_t + */ +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT +# define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT 0 +#endif + +/** + * Maximum output size in bytes allowed for DecryptCENC. + * + * 0 means no limit. + * + * Type is size_t + */ +#ifndef OPK_CONFIG_MAX_OUTPUT_SIZE_FOR_DECRYPT +# define OPK_CONFIG_MAX_OUTPUT_SIZE_FOR_DECRYPT 0 +#endif + +/** + * Maximum buffer size allowed for OEMCrpypto_Generic_*. + * + * 0 means no limit. + * + * Type is size_t + */ +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO +# define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO 0 +#endif + +/** + * Maximum sample size allowed for OEMCrypto_DecryptCENC. + * + * 0 means no limit. + * + * Type is size_t + */ +#ifndef OPK_CONFIG_MAX_SAMPLE_SIZE +# define OPK_CONFIG_MAX_SAMPLE_SIZE 0 +#endif + +/** + * Type of certificates the device can support. + * + * Result is a binary OR of bitmasks defined in OEMCryptoCENC.h + * + * Type is uint32_t + */ +#ifndef OPK_CONFIG_SUPPORTED_CERTIFICATES +# define OPK_CONFIG_SUPPORTED_CERTIFICATES \ + (OEMCrypto_Supports_RSA_CAST | OEMCrypto_Supports_RSA_2048bit) +#endif + +/** + * Whether DecryptCENC and other crypto functions are expected to be intercepted + * REE-side and rerouted to dedicated hardware, effectively bypassing the TA. + * + * A value of false means that the TA returns key handles in + * OEMCrypto_GetKeyHandle as the session ID, which is expected to be passed into + * DecryptCENC and other crypto functions as the key handle. + * + * A value of true means that the TA returns key handles in a format that is + * recognizable by dedicated hardware (eg wrapping using a known key), and the + * TEE side implementation of DecryptCENC and other crypto functions will never + * be executed. + * + * Type is bool + */ +#ifndef OPK_CONFIG_DECRYPT_BYPASSES_TA +# define OPK_CONFIG_DECRYPT_BYPASSES_TA false +#endif + +/* + * + * Config values used for static allocations + * The following values should never be more than UINT32_MAX - 1 + * + */ + +/** + * Maximum number of open sessions. + */ +#ifndef MAX_NUMBER_OF_SESSIONS +# define MAX_NUMBER_OF_SESSIONS 50 +#endif + +/** + * Maximum number of entitled key sessions. + */ +#ifndef MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS +# define MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS 20 +#endif + +/** + * Maximum number of keys across all sessions. + */ +#ifndef MAX_NUMBER_OF_KEYS +# define MAX_NUMBER_OF_KEYS 400 +#endif + +/** + * Maximum number of content keys per session. + */ +#ifndef CONTENT_KEYS_PER_SESSION +# define CONTENT_KEYS_PER_SESSION 30 +#endif + +/** + * Maximum number of entitlement keys per session. + */ +#ifndef ENTITLEMENT_KEYS_PER_SESSION +# define ENTITLEMENT_KEYS_PER_SESSION 30 +#endif + +/** + * The number of usage entries to allocate. + */ +#ifndef MAX_NUMBER_OF_USAGE_ENTRIES +# define MAX_NUMBER_OF_USAGE_ENTRIES 300 +#endif + +/** + * The number of active entries that may be loaded simultaneously. + */ +#ifndef MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES +# define MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES 10 +#endif + +/** + * The number of active DRM keys that may be loaded simultaneously. + */ +#ifndef MAX_NUMBER_OF_ASYMMETRIC_KEYS +# define MAX_NUMBER_OF_ASYMMETRIC_KEYS 16 +#endif + +/** + * The number of key slots in the layer 2 symmetric key table (if applicable) + */ +#ifndef MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES +# define MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES 8 +#endif + +/** + * Size of a wrapped MAC key + */ +#ifndef WRAPPED_MAC_KEY_SIZE +# define WRAPPED_MAC_KEY_SIZE 32 +#endif + +/** + * Size of overhead required by WTPI_EncryptAndSign (if applicable). + */ +#ifndef ENCRYPT_AND_SIGN_EXTRA +# define ENCRYPT_AND_SIGN_EXTRA 68 +#endif + +/** + * Maximum size of a symmetric (eg AES) key + */ +#ifndef MAX_SYMMETRIC_KEY_SIZE +# define MAX_SYMMETRIC_KEY_SIZE 32 +#endif + +/** + * Maximum size of a wrapped symmetric key. + */ +#ifndef MAX_WRAPPED_SYMMETRIC_KEY_SIZE +# define MAX_WRAPPED_SYMMETRIC_KEY_SIZE MAX_SYMMETRIC_KEY_SIZE +#endif + +/** + * Maximum size of a wrapped asymmetric key (ECC or RSA). + */ +#ifndef MAX_WRAPPED_ASYMMETRIC_KEY_SIZE +# define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \ + (PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA) +#endif + +/** + * Maximum size of BCC responses in Provisioning 4.0 + */ +#ifndef MAX_BCC_RESP_PAYLOAD_SIZE +# define MAX_BCC_RESP_PAYLOAD_SIZE 2048 +#endif + +/** + * Maximum size of the signature generated by an asymmetric key (ECC or RSA) + */ +#ifndef MAX_ASYMMETRIC_SIGNATURE_SIZE +# define MAX_ASYMMETRIC_SIGNATURE_SIZE 1024 +#endif + +/* + * + * Config values that must be defined by the build process. These are wrapped by + * XSTR() and used by OEMCrypto_BuildInformation and the ODK. + * + */ + +/** + * Name of the Trusted Execution Environment Operating System. + */ +#ifndef OPK_CONFIG_TEE_OS_NAME +# error "No value provided for OPK_CONFIG_TEE_OS_NAME" +#endif + +/** + * Version of the Trusted Execution Environment OS eg 1.4.10 + */ +#ifndef OPK_CONFIG_TEE_OS_VERSION +# error "No value provided for OPK_CONFIG_TEE_OS_VERSION" +#endif + +/** + * Description of the target device form factor, eg phone, tv, tablet, laptop + */ +#ifndef OPK_CONFIG_DEVICE_FORM_FACTOR +# error "No value provided for OPK_CONFIG_DEVICE_FORM_FACTOR" +#endif + +/** + * Name of the company/entity providing this build of OPK. + */ +#ifndef OPK_CONFIG_IMPLEMENTER_NAME +# error "No value provided for OPK_CONFIG_IMPLEMENTER_NAME" +#endif + +/** + * Name of the company/entity that provided the SOC for the target device + * + * This will be inserted into each ODK License request and Provisioning request. + * The name will be truncated to 16 chars for this use case. + */ +#ifndef OPK_CONFIG_SOC_VENDOR_NAME +# error "No value provided for OPK_CONFIG_SOC_VENDOR_NAME" +#endif + +/** + * Name of the SOC chipset model + * + * This will be inserted into each ODK License request and Provisioning request. + * The name will be truncated to 16 chars for this use case. + */ +#ifndef OPK_CONFIG_SOC_MODEL_NAME +# error "No value provided for OPK_CONFIG_SOC_MODEL_NAME" +#endif + +/// @} + +#endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c index 0fde11a..57f3fc5 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c @@ -10,27 +10,34 @@ #include "dice/cbor_writer.h" #include "dice/config.h" #include "dice/dice.h" -#include "ecc_util.h" #include "oemcrypto_check_macros.h" +#include "wtpi_crypto_asymmetric_interface.h" /****************************************************************************** The following are copied from open-dice library cbor_cert_op.c *******************************************************************************/ -#if DICE_PUBLIC_KEY_SIZE != 32 -# error "Only Ed25519 is supported; 32 bytes needed to store the public key." -#endif -#if DICE_SIGNATURE_SIZE != 64 -# error "Only Ed25519 is supported; 64 bytes needed to store the signature." -#endif +#define DICE_PUBLIC_KEY_SIZE_ED25519 32 +#define DICE_SIGNATURE_SIZE_ED25519 64 + +#define DICE_SIGNATURE_SIZE_P256 64 +#define DICE_PUBLIC_KEY_SIZE_P256 64 // Max size of the COSE_Sign1 protected attributes. #define DICE_MAX_PROTECTED_ATTRIBUTES_SIZE 16 -static DiceResult DiceCoseEncodePublicKey( - void* context_not_used, const uint8_t public_key[DICE_PUBLIC_KEY_SIZE], - size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { - (void)context_not_used; +static DiceResult DiceCoseEncodePublicKeyEd25519(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, + uint8_t* buffer, + size_t* encoded_size) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + if (public_key_size != DICE_PUBLIC_KEY_SIZE_ED25519) { + return kDiceResultInvalidInput; + } // Constants per RFC 8152. const int64_t kCoseKeyKtyLabel = 1; @@ -61,7 +68,7 @@ static DiceResult DiceCoseEncodePublicKey( CborWriteInt(kCoseCrvEd25519, &out); // Add the public key. CborWriteInt(kCoseOkpXLabel, &out); - CborWriteBstr(/*data_size=*/DICE_PUBLIC_KEY_SIZE, public_key, &out); + CborWriteBstr(/*data_size=*/public_key_size, public_key, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } @@ -69,18 +76,114 @@ static DiceResult DiceCoseEncodePublicKey( return kDiceResultOk; } +static DiceResult DiceCoseEncodePublicKeyECDSA(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, + uint8_t* buffer, + size_t* encoded_size) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + if (public_key_size != DICE_PUBLIC_KEY_SIZE_P256) { + return kDiceResultInvalidInput; + } + + // Constants per RFC 8152. + const int64_t kCoseKeyKtyLabel = 1; + const int64_t kCoseKeyAlgLabel = 3; + const int64_t kCoseKeyOpsLabel = 4; + const int64_t kCoseEc2CrvLabel = -1; + const int64_t kCoseEc2XLabel = -2; + const int64_t kCoseEc2YLabel = -3; + const int64_t kCoseKeyTypeEc2 = 2; + const int64_t kCoseAlgES256 = -7; + const int64_t kCoseKeyOpsVerify = 2; + const int64_t kCoseCrvP256 = 1; + + struct CborOut out; + CborOutInit(buffer, buffer_size, &out); + CborWriteMap(/*num_pairs=*/6, &out); + // Add the key type. + CborWriteInt(kCoseKeyKtyLabel, &out); + CborWriteInt(kCoseKeyTypeEc2, &out); + // Add the algorithm. + CborWriteInt(kCoseKeyAlgLabel, &out); + CborWriteInt(kCoseAlgES256, &out); + // Add the KeyOps. + CborWriteInt(kCoseKeyOpsLabel, &out); + CborWriteArray(/*num_elements=*/1, &out); + CborWriteInt(kCoseKeyOpsVerify, &out); + // Add the curve. + CborWriteInt(kCoseEc2CrvLabel, &out); + CborWriteInt(kCoseCrvP256, &out); + // Add the public key. + CborWriteInt(kCoseEc2XLabel, &out); + CborWriteBstr(/*data_size=*/public_key_size / 2, public_key, &out); + CborWriteInt(kCoseEc2YLabel, &out); + CborWriteBstr(/*data_size=*/public_key_size / 2, + public_key + (public_key_size / 2), &out); + if (CborOutOverflowed(&out)) { + return kDiceResultBufferTooSmall; + } + *encoded_size = CborOutSize(&out); + return kDiceResultOk; +} + +static DiceResult DiceCoseEncodePublicKey(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, uint8_t* buffer, + size_t* encoded_size, + AsymmetricKeyType key_type) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + LOGE("first one"); + return DiceCoseEncodePublicKeyEd25519(public_key, public_key_size, + buffer_size, buffer, encoded_size); + + case DRM_ECC_PRIVATE_KEY: + LOGE("second one"); + return DiceCoseEncodePublicKeyECDSA(public_key, public_key_size, + buffer_size, buffer, encoded_size); + default: + return kDiceResultInvalidInput; + } + return kDiceResultInvalidInput; +} + static DiceResult EncodeProtectedAttributes(size_t buffer_size, uint8_t* buffer, - size_t* encoded_size) { + size_t* encoded_size, + AsymmetricKeyType key_type) { + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + // Constants per RFC 8152. const int64_t kCoseHeaderAlgLabel = 1; const int64_t kCoseAlgEdDSA = -8; + const int64_t kCoseAlgES256 = -7; + + int64_t coseAlg = kCoseAlgEdDSA; + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + coseAlg = kCoseAlgEdDSA; + break; + case DRM_ECC_PRIVATE_KEY: + coseAlg = kCoseAlgES256; + break; + default: + return kDiceResultInvalidInput; + } struct CborOut out; CborOutInit(buffer, buffer_size, &out); CborWriteMap(/*num_pairs=*/1, &out); // Add the algorithm. CborWriteInt(kCoseHeaderAlgLabel, &out); - CborWriteInt(kCoseAlgEdDSA, &out); + CborWriteInt(coseAlg, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } @@ -94,6 +197,12 @@ static DiceResult EncodeCoseTbs(const uint8_t* protected_attributes, const uint8_t* aad, size_t aad_size, size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { + ABORT_IF_NULL(protected_attributes); + ABORT_IF_NULL(payload); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + // aad is specifically allowed to be null + struct CborOut out; CborOutInit(buffer, buffer_size, &out); // TBS is an array of four elements. @@ -116,9 +225,14 @@ static DiceResult EncodeCoseTbs(const uint8_t* protected_attributes, static DiceResult EncodeCoseSign1(const uint8_t* protected_attributes, size_t protected_attributes_size, const uint8_t* payload, size_t payload_size, - const uint8_t signature[DICE_SIGNATURE_SIZE], - size_t buffer_size, uint8_t* buffer, - size_t* encoded_size) { + const uint8_t* signature, + size_t signature_size, size_t buffer_size, + uint8_t* buffer, size_t* encoded_size) { + if (signature_size != DICE_SIGNATURE_SIZE_ED25519 || + signature_size != DICE_SIGNATURE_SIZE_P256) { + return kDiceResultInvalidInput; + } + struct CborOut out; CborOutInit(buffer, buffer_size, &out); // COSE_Sign1 is an array of four elements. @@ -130,26 +244,26 @@ static DiceResult EncodeCoseSign1(const uint8_t* protected_attributes, // Payload. CborWriteBstr(payload_size, payload, &out); // Signature. - CborWriteBstr(/*num_elements=*/DICE_SIGNATURE_SIZE, signature, &out); + CborWriteBstr(/*num_elements=*/signature_size, signature, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } *encoded_size = CborOutSize(&out); return kDiceResultOk; } -/****************************************************************************** - The codes above are copied from open-dice library cbor_cert_op.c -*******************************************************************************/ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t payload_size, - const uint8_t* ed25519_key, + AsymmetricKeyType key_type, + WTPI_AsymmetricKey_Handle key, size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { - if (payload == NULL || payload_size == 0 || ed25519_key == NULL || - buffer_size == 0 || buffer == NULL || encoded_size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + RETURN_INVALID_CONTEXT_IF_NULL(payload); + RETURN_INVALID_CONTEXT_IF_ZERO(payload_size); + RETURN_INVALID_CONTEXT_IF_NULL(key); + RETURN_INVALID_CONTEXT_IF_ZERO(buffer_size); + RETURN_INVALID_CONTEXT_IF_NULL(buffer); + RETURN_INVALID_CONTEXT_IF_NULL(encoded_size); *encoded_size = 0; // The encoded protected attributes are used in the TBS and the final @@ -158,7 +272,7 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t protected_attributes_size = 0; DiceResult dice_result = EncodeProtectedAttributes( sizeof(protected_attributes), protected_attributes, - &protected_attributes_size); + &protected_attributes_size, key_type); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -173,24 +287,70 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, } // Sign the TBS with the authority key. - uint8_t signature[DICE_SIGNATURE_SIZE]; + uint8_t signature[DICE_SIGNATURE_SIZE_P256]; // P256 is largest supported so size_t signature_length = sizeof(signature); - OEMCryptoResult result = ED25519Sign(ed25519_key, buffer, *encoded_size, - signature, &signature_length); + OEMCryptoResult result = CoseSignOp(key, key_type, buffer, *encoded_size, + signature, &signature_length); if (result != OEMCrypto_SUCCESS) { return result; } // The final certificate is an untagged COSE_Sign1 structure. - dice_result = EncodeCoseSign1(protected_attributes, protected_attributes_size, - payload, payload_size, signature, buffer_size, - buffer, encoded_size); + dice_result = EncodeCoseSign1( + protected_attributes, protected_attributes_size, payload, payload_size, + signature, signature_length, buffer_size, buffer, encoded_size); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } return OEMCrypto_SUCCESS; } +/****************************************************************************** + The following are added by Widevine +*******************************************************************************/ + +// The minimum buffer length required to hold the generated BCC. The generated +// BCC should have a fixed size in phase 1. +#define BCC_TOTAL_LENGTH_ED25519 184 +#define BCC_TOTAL_LENGTH_P256 254 + +#if BCC_TOTAL_LENGTH_ED25519 >= BCC_TOTAL_LENGTH_P256 +# define BCC_MAX_LENGTH BCC_TOTAL_LENGTH_ED25519 +#else +# define BCC_MAX_LENGTH BCC_TOTAL_LENGTH_P256 +#endif + +// CSR is defined in: +// https://source.corp.google.com/android/hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl +#define CSR_PAYLOAD_MAX_LENGTH 2048 + +// The max length of a string field in device CBOR map +#define DEVICE_TSTR_MAX_LENGTH 64 +// The max length of certain string fields which have constant string values in +// device CBOR map +#define DEVICE_TSTR_SHORT_MAX_LENGTH 16 +// Device info is defined in: +// https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl +typedef struct { + // TSTR fields with DEVICE_TSTR_MAX_LENGTH need an extra space for null + // termination + char brand[DEVICE_TSTR_MAX_LENGTH + 1]; + char manufacturer[DEVICE_TSTR_MAX_LENGTH + 1]; + char product[DEVICE_TSTR_MAX_LENGTH + 1]; + char model[DEVICE_TSTR_MAX_LENGTH + 1]; + char device[DEVICE_TSTR_MAX_LENGTH + 1]; + char vb_state[DEVICE_TSTR_SHORT_MAX_LENGTH]; + char bootloader_state[DEVICE_TSTR_SHORT_MAX_LENGTH]; + uint8_t vbmeta_digest[64]; + size_t vbmeta_digest_size; + char os_version[DEVICE_TSTR_MAX_LENGTH + 1]; + uint64_t system_patch_level; + uint64_t boot_patch_level; + uint64_t vendor_patch_level; + char security_level[DEVICE_TSTR_SHORT_MAX_LENGTH]; + int64_t fused; +} DeviceInfo; + static OEMCryptoResult GenerateEncodedBccPayload( const uint8_t* encoded_public_key, size_t encoded_public_key_size, uint8_t* out, size_t* out_length) { @@ -200,13 +360,23 @@ static OEMCryptoResult GenerateEncodedBccPayload( ABORT_IF_NULL(out_length); ABORT_IF_ZERO(*out_length); + const int64_t kIssuerLabel = 1; + const int64_t kSubjectLabel = 2; const int64_t kSubjectPublicKeyLabel = -4670552; const int64_t kKeyUsageLabel = -4670553; const uint8_t kKeyUsageCertSign = 32; struct CborOut cbor_out; CborOutInit(out, *out_length, &cbor_out); - CborWriteMap(/*num_pairs=*/2, &cbor_out); + CborWriteMap(/*num_pairs=*/4, &cbor_out); + // Add mandatory field Issuer, which is ignored by provisioning server and can + // be empty. + CborWriteInt(kIssuerLabel, &cbor_out); + CborWriteTstr("", &cbor_out); + // Add mandatory field Subject, which is ignored by provisioning server and + // can be empty. + CborWriteInt(kSubjectLabel, &cbor_out); + CborWriteTstr("", &cbor_out); // Add the subject public key. CborWriteInt(kSubjectPublicKeyLabel, &cbor_out); CborWriteBstr(encoded_public_key_size, encoded_public_key, &cbor_out); @@ -220,27 +390,318 @@ static OEMCryptoResult GenerateEncodedBccPayload( return OEMCrypto_SUCCESS; } -// The minimum buffer length required to hold the generated BCC. The generated -// BCC should have a fixed size in phase 1. In this implementation, it happens -// to be 180 bytes. -#define BCC_TOTAL_LENGTH 180 +// Read the next Tstr value from device Cbor map and place the result in |val|. +static OEMCryptoResult ReadDeviceInfoMapTstrWithKey(struct CborIn* in, + const char* key, + size_t max_length, + char* val) { + const char* val_str; + size_t val_str_size = 0; + if (CborReadTstr(in, &val_str_size, &val_str) != CBOR_READ_RESULT_OK) { + LOGE("Failed to read %s value from device_info map", key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (val_str_size > max_length) { + LOGW("%s size is too large: %zu, max_length: %zu, truncated.", key, + val_str_size, max_length); + val_str_size = max_length; + } + memcpy(val, val_str, val_str_size); + return OEMCrypto_SUCCESS; +} + +// Read the next Bstr value from device Cbor map and place the result in |val| +// and |val_size|. +static OEMCryptoResult ReadDeviceInfoMapBstrWithKey(struct CborIn* in, + const char* key, + size_t max_length, + uint8_t* val, + size_t* val_size) { + const uint8_t* val_bstr; + size_t val_bstr_size = 0; + if (CborReadBstr(in, &val_bstr_size, &val_bstr) != CBOR_READ_RESULT_OK) { + LOGE("Failed to read %s value from device_info map", key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (val_bstr_size > max_length) { + LOGW("%s size is too large: %zu, max_length: %zu, truncated.", key, + val_bstr_size, max_length); + val_bstr_size = max_length; + } + memcpy(val, val_bstr, val_bstr_size); + *val_size = val_bstr_size; + return OEMCrypto_SUCCESS; +} + +// Read the next uint value from device and place the result in |val|. +static OEMCryptoResult ReadDeviceInfoMapUintWithKey(struct CborIn* in, + const char* key, + uint64_t* val) { + if (CborReadUint(in, val) != CBOR_READ_RESULT_OK) { + LOGE("Failed to read %s value from device_info map", key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +// Decode |encoded_device_info| and write it to |cbor_csr_out|. +static OEMCryptoResult DecodeAndWriteDeviceInfo( + struct CborOut* cbor_csr_out, const uint8_t* encoded_device_info, + size_t encoded_device_info_size) { + struct CborIn in; + size_t item_count; + CborInInit(encoded_device_info, encoded_device_info_size, &in); + if (CborReadMap(&in, &item_count) != CBOR_READ_RESULT_OK) { + LOGE("encoded_device_info is not a valid CBOR map."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + const char* kBrand = "brand"; + const char* kManufacturer = "manufacturer"; + const char* kProduct = "product"; + const char* kModel = "model"; + const char* kDevice = "device"; + const char* kVbState = "vb_state"; + const char* kBootloaderState = "bootloader_state"; + const char* kVbmetaDigest = "vbmeta_digest"; + const char* kOsVersion = "os_version"; + const char* kSystemPatchLevel = "system_patch_level"; + const char* kBootPatchLevel = "boot_patch_level"; + const char* kVendorPatchLevel = "vendor_patch_level"; + const char* kSecurityLevel = "security_level"; + const char* kFused = "fused"; + // Total count of the fields above to be written. + const size_t kNumPairs = 14; + + OEMCryptoResult result = OEMCrypto_SUCCESS; + DeviceInfo deviceInfo; + memset(&deviceInfo, 0, sizeof(deviceInfo)); + for (size_t i = 0; i < item_count; ++i) { + const char* raw_key; + size_t key_size = 0; + if (CborReadTstr(&in, &key_size, &raw_key) != CBOR_READ_RESULT_OK) { + LOGE("Failed to read key from device_info map at index: %zu", i); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Null-terminating string to hold |raw_key| + char key[DEVICE_TSTR_MAX_LENGTH] = {0}; + if (key_size > sizeof(key) - 1) { + LOGE("Device info map key size too large: %zu", key_size); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memcpy(key, raw_key, key_size); + if (strcmp(key, kBrand) == 0) { + result = ReadDeviceInfoMapTstrWithKey(&in, kBrand, DEVICE_TSTR_MAX_LENGTH, + deviceInfo.brand); + } else if (strcmp(key, kManufacturer) == 0) { + result = ReadDeviceInfoMapTstrWithKey( + &in, kManufacturer, DEVICE_TSTR_MAX_LENGTH, deviceInfo.manufacturer); + } else if (strcmp(key, kProduct) == 0) { + result = ReadDeviceInfoMapTstrWithKey( + &in, kProduct, DEVICE_TSTR_MAX_LENGTH, deviceInfo.product); + } else if (strcmp(key, kModel) == 0) { + result = ReadDeviceInfoMapTstrWithKey(&in, kModel, DEVICE_TSTR_MAX_LENGTH, + deviceInfo.model); + } else if (strcmp(key, kDevice) == 0) { + result = ReadDeviceInfoMapTstrWithKey( + &in, kDevice, DEVICE_TSTR_MAX_LENGTH, deviceInfo.device); + } else if (strcmp(key, kVbState) == 0) { + result = ReadDeviceInfoMapTstrWithKey( + &in, kVbState, DEVICE_TSTR_SHORT_MAX_LENGTH, deviceInfo.vb_state); + } else if (strcmp(key, kBootloaderState) == 0) { + result = ReadDeviceInfoMapTstrWithKey(&in, kBootloaderState, + DEVICE_TSTR_SHORT_MAX_LENGTH, + deviceInfo.bootloader_state); + } else if (strcmp(key, kVbmetaDigest) == 0) { + result = ReadDeviceInfoMapBstrWithKey( + &in, kVbmetaDigest, sizeof(deviceInfo.vbmeta_digest), + deviceInfo.vbmeta_digest, &deviceInfo.vbmeta_digest_size); + } else if (strcmp(key, kOsVersion) == 0) { + result = ReadDeviceInfoMapTstrWithKey( + &in, kOsVersion, DEVICE_TSTR_MAX_LENGTH, deviceInfo.os_version); + } else if (strcmp(key, kSystemPatchLevel) == 0) { + result = ReadDeviceInfoMapUintWithKey(&in, kSystemPatchLevel, + &deviceInfo.system_patch_level); + } else if (strcmp(key, kBootPatchLevel) == 0) { + result = ReadDeviceInfoMapUintWithKey(&in, kBootPatchLevel, + &deviceInfo.boot_patch_level); + } else if (strcmp(key, kVendorPatchLevel) == 0) { + result = ReadDeviceInfoMapUintWithKey(&in, kVendorPatchLevel, + &deviceInfo.vendor_patch_level); + } else if (strcmp(key, kSecurityLevel) == 0) { + result = ReadDeviceInfoMapTstrWithKey(&in, kSecurityLevel, + DEVICE_TSTR_SHORT_MAX_LENGTH, + deviceInfo.security_level); + } else if (strcmp(key, kFused) == 0) { + if (CborReadInt(&in, &deviceInfo.fused) != CBOR_READ_RESULT_OK) { + LOGE("Failed to read %s value from device_info map", kFused); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } else { + // Ignore the next value. + if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) { + LOGE("Failed to skip a device map value."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + if (result != OEMCrypto_SUCCESS) return result; + } + + // Write the decoded device info map. + CborWriteMap(kNumPairs, cbor_csr_out); + // Write key-values in canonical order: + // boot_patch_level + // bootloader_state + // brand + // device + // fused + // manufacturer + // model + // os_version + // product + // security_level + // system_patch_level + // vb_state + // vbmeta_digest + // vendor_patch_level + CborWriteTstr(kBootPatchLevel, cbor_csr_out); + CborWriteUint(deviceInfo.boot_patch_level, cbor_csr_out); + + CborWriteTstr(kBootloaderState, cbor_csr_out); + CborWriteTstr(deviceInfo.bootloader_state, cbor_csr_out); + + CborWriteTstr(kBrand, cbor_csr_out); + CborWriteTstr(deviceInfo.brand, cbor_csr_out); + + CborWriteTstr(kDevice, cbor_csr_out); + CborWriteTstr(deviceInfo.device, cbor_csr_out); + + CborWriteTstr(kFused, cbor_csr_out); + CborWriteInt(deviceInfo.fused, cbor_csr_out); + + CborWriteTstr(kManufacturer, cbor_csr_out); + CborWriteTstr(deviceInfo.manufacturer, cbor_csr_out); + + CborWriteTstr(kModel, cbor_csr_out); + CborWriteTstr(deviceInfo.model, cbor_csr_out); + + CborWriteTstr(kOsVersion, cbor_csr_out); + CborWriteTstr(deviceInfo.os_version, cbor_csr_out); + + CborWriteTstr(kProduct, cbor_csr_out); + CborWriteTstr(deviceInfo.product, cbor_csr_out); + + CborWriteTstr(kSecurityLevel, cbor_csr_out); + CborWriteTstr(deviceInfo.security_level, cbor_csr_out); + + CborWriteTstr(kSystemPatchLevel, cbor_csr_out); + CborWriteUint(deviceInfo.system_patch_level, cbor_csr_out); + + CborWriteTstr(kVbState, cbor_csr_out); + CborWriteTstr(deviceInfo.vb_state, cbor_csr_out); + + CborWriteTstr(kVbmetaDigest, cbor_csr_out); + CborWriteBstr(deviceInfo.vbmeta_digest_size, deviceInfo.vbmeta_digest, + cbor_csr_out); + + CborWriteTstr(kVendorPatchLevel, cbor_csr_out); + CborWriteUint(deviceInfo.vendor_patch_level, cbor_csr_out); + + if (CborOutOverflowed(cbor_csr_out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult GenerateCsrPayload(const uint8_t* challenge, + size_t challenge_size, + const uint8_t* encoded_device_info, + size_t encoded_device_info_size, + uint8_t* out, size_t* out_length) { + if (out == NULL || out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (challenge == NULL && challenge_size != 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encoded_device_info == NULL && encoded_device_info_size != 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // Write CsrPayload cbor struct + // 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 DeviceInfo.aidl + // KeysToSign, ; Provided by the method parameters + // ]; + const int64_t kSchemaVersion = 3; + uint8_t csr_payload[CSR_PAYLOAD_MAX_LENGTH]; + size_t csr_payload_size = sizeof(csr_payload); + struct CborOut cbor_csr_out; + CborOutInit(csr_payload, csr_payload_size, &cbor_csr_out); + CborWriteArray(/*num_elements=*/4, &cbor_csr_out); + CborWriteInt(kSchemaVersion, &cbor_csr_out); + // CertificateType + CborWriteTstr("widevine", &cbor_csr_out); + // DeviceInfo + OEMCryptoResult result = DecodeAndWriteDeviceInfo( + &cbor_csr_out, encoded_device_info, encoded_device_info_size); + if (result != OEMCrypto_SUCCESS) return result; + // KeysToSign + CborWriteArray(/*num_elements=*/0, &cbor_csr_out); + if (CborOutOverflowed(&cbor_csr_out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + csr_payload_size = CborOutSize(&cbor_csr_out); + + // Write SignedData cbor struct, which is to be signed by the BCC + // leaf cert. + // SignedData = [ + // challenge: bstr .size (32..64), + // bstr .cbor CsrPayload, + // ]; + struct CborOut cbor_signed_csr_out; + CborOutInit(out, *out_length, &cbor_signed_csr_out); + CborWriteArray(/*num_elements=*/2, &cbor_signed_csr_out); + // Challenge + CborWriteBstr(challenge_size, challenge, &cbor_signed_csr_out); + // CsrPayload + CborWriteBstr(csr_payload_size, csr_payload, &cbor_signed_csr_out); + if (CborOutOverflowed(&cbor_signed_csr_out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *out_length = CborOutSize(&cbor_signed_csr_out); + return OEMCrypto_SUCCESS; +} OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t public_key_length, AsymmetricKeyType key_type, - const uint8_t* ed25519_key, + WTPI_AsymmetricKey_Handle key, uint8_t* out, size_t* out_length) { - if (public_key == NULL || out_length == NULL || ed25519_key == NULL) { + if (public_key == NULL || out_length == NULL || key == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (out == NULL || *out_length < BCC_TOTAL_LENGTH) { - *out_length = BCC_TOTAL_LENGTH; - return OEMCrypto_ERROR_SHORT_BUFFER; + + size_t required_buffer_length = BCC_MAX_LENGTH; + // Can only support ED25519 and ECDSA P256 + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + if (public_key_length != DICE_PUBLIC_KEY_SIZE_ED25519) + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + break; + case DRM_ECC_PRIVATE_KEY: + if (public_key_length != DICE_PUBLIC_KEY_SIZE_P256) + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + break; + default: + return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - // Can only support ED25519 key. - if (key_type != PROV40_ED25519_PRIVATE_KEY || - public_key_length != DICE_PUBLIC_KEY_SIZE) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + + if (out == NULL || *out_length < required_buffer_length) { + *out_length = required_buffer_length; + return OEMCrypto_ERROR_SHORT_BUFFER; } // Bcc = [ @@ -261,8 +722,8 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, const uint8_t* encoded_public_key = out + out_cursor; size_t encoded_public_key_size = 0; DiceResult dice_result = DiceCoseEncodePublicKey( - /*context_not_used=*/NULL, public_key, *out_length - out_cursor, - out + out_cursor, &encoded_public_key_size); + public_key, public_key_length, *out_length - out_cursor, out + out_cursor, + &encoded_public_key_size, key_type); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -270,7 +731,7 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, // Encode second entry in the array which is a COSE_Sign1. // The payload can not exceed total length. - uint8_t bcc_payload[BCC_TOTAL_LENGTH]; + uint8_t bcc_payload[BCC_MAX_LENGTH]; size_t bcc_payload_size = sizeof(bcc_payload); OEMCryptoResult result = GenerateEncodedBccPayload(encoded_public_key, encoded_public_key_size, @@ -279,7 +740,7 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t encoded_cose_sign1_size = 0; result = DiceCoseSignAndEncodeSign1( - bcc_payload, bcc_payload_size, ed25519_key, *out_length - out_cursor, + bcc_payload, bcc_payload_size, key_type, key, *out_length - out_cursor, out + out_cursor, &encoded_cose_sign1_size); if (result != OEMCrypto_SUCCESS) return result; out_cursor += encoded_cose_sign1_size; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h index d573abe..846c7d2 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h @@ -7,16 +7,18 @@ #include "OEMCryptoCENCCommon.h" #include "oemcrypto_key_types.h" +#include "wtpi_crypto_asymmetric_interface.h" /** - * Generate a COSE_SIGN1 format signature of |payload| with |ed25519_key| and - * wirte the signature to |buffer|. Only ED25519 key is currently supported. + * Generate a COSE_SIGN1 format signature of |payload| with |key| and + * write the signature to |buffer|. + * * Caller retains ownership of all pointers and they must not be NULL. - * |ed25519_key| is expected to be size ED25519_PRIVATE_KEY_LEN. */ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t payload_size, - const uint8_t* ed25519_key, + AsymmetricKeyType key_type, + WTPI_AsymmetricKey_Handle key, size_t buffer_size, uint8_t* buffer, size_t* encoded_size); @@ -30,8 +32,9 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t public_key_length, AsymmetricKeyType key_type, - const uint8_t* ed25519_key, + WTPI_AsymmetricKey_Handle key, uint8_t* out, size_t* out_length); + /** * Parse the input BCC and retrieve the encoded device public key (COSE_key). */ @@ -39,4 +42,23 @@ OEMCryptoResult GetDevicePublicKeyFromBcc(const uint8_t* bcc, size_t bcc_length, uint8_t* dk_pub, size_t* dk_pub_length); +/** + * Sign |message| with |key| and place the result in |signature|. Update + * |signature_length| to reflect the bytes written to |signature|. + */ +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type, const uint8_t* message, + size_t message_size, uint8_t* signature, + size_t* signature_length); + +/** + * Write the serialized CsrPayload CBOR structure in |out|. Update + * |out_length| to reflect the bytes written to |out|. + */ +OEMCryptoResult GenerateCsrPayload(const uint8_t* challenge, + size_t challenge_size, + const uint8_t* encoded_device_info, + size_t encoded_device_info_size, + uint8_t* out, size_t* out_length); + #endif /* OEMCRYPTO_TA_COSE_UTIL_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.c new file mode 100644 index 0000000..c2592d2 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.c @@ -0,0 +1,45 @@ +/* Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "device_key_util.h" + +#include + +#include "OEMCryptoCENCCommon.h" +#include "crypto_util.h" +#include "wtpi_abort_interface.h" +#include "wtpi_device_key_access_interface.h" + +OEMCryptoResult DeriveFromDeviceKey(uint32_t context, + SymmetricKeyType out_key_type, + uint8_t* out_key, KeySize out_key_size) { + ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); + ABORT_IF(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256, + "Invalid key size"); + + const uint8_t* device_key = WTPI_GetDeviceKey(); + KeySize device_key_size = WTPI_GetDeviceKeySize(); + // Prepare full context for key derivation + // Server and client MAC keys must derive to the same key. + const SymmetricKeyType type_temp = + out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type; + // Cast the type into 32 bits so it is the same size as the gap left for it in + // full_context. This will be a no-op on most architectures. + const uint32_t type_32 = (uint32_t)type_temp; + // Build a full context that is unique to this starting context / key type + // combination. We start with a context template with blanks at the beginning + // and fill the blanks with the starting context and key type. + uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', + 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; + const size_t context_length = sizeof(full_context); + memcpy(full_context, &context, 4); + memcpy(full_context + 4, &type_32, 4); + const uint8_t counter = 1; + if (!OPKI_DeriveKeyWithCMAC(device_key, device_key_size, counter, + full_context, context_length, out_key_size, + out_key)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.h new file mode 100644 index 0000000..810550e --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key_util.h @@ -0,0 +1,20 @@ +/* Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#ifndef OEMCRYPTO_TA_DEVICE_KEY_UTIL_H_ +#define OEMCRYPTO_TA_DEVICE_KEY_UTIL_H_ + +#include "OEMCryptoCENCCommon.h" +#include "oemcrypto_key_types.h" + +/** + * Derives a key from the device key with |context|, and the specified + * |out_key_type| and |out_key_size|. Places the result in |out_key|. Caller + * retains ownership of all pointers. + */ +OEMCryptoResult DeriveFromDeviceKey(uint32_t context, + SymmetricKeyType out_key_type, + uint8_t* out_key, KeySize out_key_size); + +#endif /* OEMCRYPTO_TA_DEVICE_KEY_UTIL_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.c index 8d0806d..57052dd 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.c @@ -33,7 +33,7 @@ /* Returns the OpenSSL defined curve ID. Otherwise 0 is returned. Caller may assume that any error details will be logged. */ static int GetCurveId(const EC_KEY* key) { - const EC_GROUP* group = EC_KEY_get0_group(key); + const EC_GROUP* const group = EC_KEY_get0_group(key); if (group == NULL) { LOGE("EC_KEY_get0_group returned NULL"); dump_ssl_error(); @@ -41,7 +41,7 @@ static int GetCurveId(const EC_KEY* key) { } const int curve = EC_GROUP_get_curve_name(group); switch (curve) { - case 0: /* No NID or error */ + case NID_undef: /* No NID or error */ /* This is possible if the provided deserialized key used deprecated curve parameters. Although it is possible that the curve parameters are valid, keys using curve parameters should be rejected. */ @@ -66,6 +66,26 @@ bool CheckECCKey(const EC_KEY* ecc_key) { return false; } +bool GetECCKeyECDSAHashAlgorithm( + const EC_KEY* ecc_key, OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + const int curve = GetCurveId(ecc_key); + // This should match the similar switch statement in ECCSignECDSA() where the + // hashing is done. + switch (curve) { + case NIST_P256: + *hash_algorithm = OEMCrypto_SHA2_256; + return true; + case NIST_P384: + *hash_algorithm = OEMCrypto_SHA2_384; + return true; + case NIST_P521: + *hash_algorithm = OEMCrypto_SHA2_512; + return true; + default: + return false; + } +} + bool DeserializeECCPrivateKey(const uint8_t* serialized_bytes, size_t size, EC_KEY** ecc_key) { ABORT_IF(serialized_bytes == NULL || size <= 0 || ecc_key == NULL, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.h index 816063d..9af3969 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.h @@ -8,7 +8,7 @@ #include "stdbool.h" #include "stdint.h" -#include "OEMCryptoCENCCommon.h" +#include "OEMCryptoCENC.h" #include "openssl/ec.h" /* Checks to see that |ecc_key| is a valid ECC key. Returns false if not a @@ -16,6 +16,11 @@ Caller retains ownership of |ecc_key| and it must not be NULL. */ bool CheckECCKey(const EC_KEY* ecc_key); +/* Gets the hash function that would be used if |ecc_key| were used for ECDSA + signing. */ +bool GetECCKeyECDSAHashAlgorithm( + const EC_KEY* ecc_key, OEMCrypto_SignatureHashAlgorithm* hash_algorithm); + /* Attempts to deserialize |size| bytes of |serialized_bytes| into an ECC key and store the result in |ecc_key|. The provided |serialized_bytes| must contain a valid ASN.1 DER encoded diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.c index e428d2d..ba70d8d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.c @@ -81,17 +81,18 @@ cleanup: return success; } -bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length, - uint8_t* signature, size_t* signature_length) { +bool RSASignSSAPSSSHA256(RSA* rsa, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) { ABORT_IF(rsa == NULL || message == NULL || message_length <= 0 || signature == NULL || signature_length == NULL, "Parameters are NULL or 0"); size_t private_key_size = RSA_size(rsa); ABORT_IF(*signature_length < private_key_size, "signature_length is not long enough"); - /* Hash the message using SHA1. */ - uint8_t hash[SHA_DIGEST_LENGTH]; - if (!SHA1(message, message_length, hash)) { + /* Hash the message using SHA256. */ + uint8_t hash[SHA256_DIGEST_LENGTH]; + if (!SHA256(message, message_length, hash)) { dump_ssl_error(); return false; } @@ -99,8 +100,8 @@ bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length, ABORT_IF(private_key_size > KEY_SIZE_3072, "rsa size is too large"); uint8_t padding[KEY_SIZE_3072]; const int kPssSaltLength = 20; - int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padding, hash, EVP_sha1(), - NULL, kPssSaltLength); + int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padding, hash, EVP_sha256(), + EVP_sha1(), kPssSaltLength); if (status == 0) { dump_ssl_error(); return false; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.h index 654ab4f..1f8f9ba 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.h @@ -27,13 +27,14 @@ bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size, RSA** rsa); /* Signs |message_length| bytes of |message| using |rsa| and padding scheme - RSASSA-PSS with SHA1 and places the result in |signature| and modifies + RSASSA-PSS with SHA-256 and places the result in |signature| and modifies *|signature_length| to the appropriate value. Returns false if the signature could not be computed. |message_length| must be > 0 and *|signature_length| must be > RSA_size(rsa). Caller retains ownership of all pointers and they must not be NULL. */ -bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length, - uint8_t* signature, size_t* signature_length); +bool RSASignSSAPSSSHA256(RSA* rsa, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length); /* Decrypts |in_length| bytes of |in| and places it in |out| using scheme PKCS1 OAEP and |rsa|. Modifies *|out_length| to the appropriate length. diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c index 4169d2c..3265da3 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c @@ -13,6 +13,7 @@ #include "oemcrypto_wall_clock.h" #include "wtpi_clock_interface_layer2.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_generation_number_interface.h" #include "wtpi_logging_interface.h" #include "wtpi_persistent_storage.h" @@ -56,15 +57,11 @@ static OEMCryptoResult InitializeDelta(void) { wall_clock > gSavedWallClock) { uint64_t sleep_time = wall_clock - gSavedWallClock; gLastTime += sleep_time; - LOGD("Init clock from sleep time = %" PRIu64 " = %" PRIu64 " - %" PRIu64, - sleep_time, wall_clock, gSavedWallClock); } // After that onetime increment, we should advance the clock in sync with the // hardware clock. Here we compute the delta between our system clock and the // hardware clock. gClockDelta = gLastTime - hw_timer; - LOGD("Init clock with new delta: %" PRId64 " = %" PRIu64 " - %" PRIu64, - gClockDelta, gLastTime, hw_timer); return OEMCrypto_SUCCESS; } @@ -87,7 +84,14 @@ static OEMCryptoResult InitializeData(void) { gClockDelta = 0; gLastSaveTime = 0; status = WTPI_GetSecureTimer(&gLastTime); - LOGD("Initializing new clock delta = 0, last = %" PRIu64, gLastTime); + // Some duration logic assumes a clock value of 0 can never happen, so let's + // pick a minimum clock value. + const uint64_t kMinimumClock = 10; + if (gLastTime < kMinimumClock) { + gLastTime += kMinimumClock; + gClockDelta += kMinimumClock; + gLastSaveTime += kMinimumClock; + } return status; } else { WTPI_PersistentData data; @@ -97,10 +101,6 @@ static OEMCryptoResult InitializeData(void) { gSavedWallClock = data.previous_wall_clock; gLastSaveTime = gLastTime; status = InitializeDelta(); - LOGD("Loading saved generation: %" PRIu64, gSavedGenerationNumber); - LOGD("Initializing clock w/last = %" PRIu64 ", last wall = %" PRIu64 - ", delta = %" PRId64, - gLastTime, gSavedWallClock, gClockDelta); return status; } } @@ -117,10 +117,7 @@ static OEMCryptoResult SaveData(void) { wall_clock > EARLIEST_REASONABLE_TIME ? wall_clock : gSavedWallClock; data.previous_trusted_time = gLastTime; data.generation_number = gSavedGenerationNumber; - LOGD("Store generation number = %" PRIu64, gSavedGenerationNumber); gLastSaveTime = gLastTime; - LOGD("Saving wall clock = %" PRIu64 ", system time = %" PRId64 ".", - data.previous_wall_clock, data.previous_trusted_time); size_t data_length = PERSISTENT_DATA_SIZE; uint8_t buffer[PERSISTENT_DATA_SIZE]; buffer[0] = PERSISTENT_FORMAT_VERSION_NUMBER; @@ -136,7 +133,6 @@ OEMCryptoResult WTPI_PrepareGenerationNumber(void) { } OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { - LOGD("Load generation number."); if (!gInitialized) { OEMCryptoResult status = InitializeData(); if (status != OEMCrypto_SUCCESS) return status; @@ -147,7 +143,6 @@ OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { } OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { - LOGD("Save generation number."); if (!gInitialized) { // This is only done in the tests. In real life, we attempt to load the old // GN before we ever save a new one. @@ -162,7 +157,6 @@ OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { The following implement the clock interface. *******************************************************************************/ OEMCryptoResult WTPI_InitializeClock(void) { - LOGD("Initialize clock."); gInitialized = false; gLastTime = 0; gSavedWallClock = EARLIEST_REASONABLE_TIME; @@ -172,7 +166,6 @@ OEMCryptoResult WTPI_InitializeClock(void) { } OEMCryptoResult WTPI_TerminateClock(void) { - LOGD("Terminate clock."); if (!gInitialized) return OEMCrypto_SUCCESS; return SaveData(); } @@ -183,7 +176,6 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { RETURN_INVALID_CONTEXT_IF_NULL(time_in_s); OEMCryptoResult status = OEMCrypto_SUCCESS; if (!gInitialized) { - LOGD("Clock needs to initialize."); status = InitializeData(); if (status != OEMCrypto_SUCCESS) return status; } @@ -205,8 +197,6 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { } *time_in_s = now; if (now > gLastSaveTime + PERIODIC_SAVE_TIME) { - LOGD("Periodic clock save. now = %" PRIu64 ", last save = %" PRIu64, now, - gLastSaveTime); SaveData(); } return status; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config.c new file mode 100644 index 0000000..ce7b0dc --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config.c @@ -0,0 +1,99 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#include "config/default.h" +#include "opk_config.h" + +#include "wtpi_config_interface.h" + +OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) { + return OPK_CONFIG_SECURITY_LEVEL; +} + +OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { + return OPK_CONFIG_PROVISIONING_METHOD; +} + +uint32_t WTPI_GetResourceRatingTier(void) { + return OPK_CONFIG_RESOURCE_RATING_TIER; +} + +OPK_FeatureStatus WTPI_IsTAAntiRollbackEnabled(void) { + return OPK_CONFIG_TA_ANTIROLLBACK_SUPPORTED; +} + +bool WTPI_IsProductionReady(void) { return false; } + +OEMCrypto_WatermarkingSupport WTPI_GetWatermarkingSupport(void) { + return OPK_CONFIG_WATERMARKING_SUPPORT; +} + +OEMCrypto_DTCP2_Capability WTPI_GetDTCP2Capability(void) { + return OEMCrypto_NO_DTCP2; +} + +OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) { + if (srm_version == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *srm_version = 0; + return OEMCrypto_SUCCESS; +} + +bool WTPI_IsAntiRollbackHWPresent(void) { + return OPK_CONFIG_HW_ANTIROLLBACK_SUPPORTED; +} + +OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field) { + (void)cgms_field; + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +bool WTPI_IsCGMS_AActive(void) { return false; } + +bool WTPI_SupportsCGMS_A(void) { return OPK_CONFIG_SUPPORTS_CGMSA; } + +bool WTPI_HasAnalogDisplay(void) { return OPK_CONFIG_HAS_ANALOG_DISPLAY; } + +bool WTPI_IsAnalogDisplayActive(void) { return false; } + +bool WTPI_CanDisableAnalogDisplay(void) { + return OPK_CONFIG_CAN_DISABLE_ANALOG_DISPLAY; +} + +bool WTPI_DisableAnalogDisplay(void) { return false; } + +size_t WTPI_MaxBufferSizeForDecrypt(void) { + return OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT; +} + +size_t WTPI_MaxOutputSizeForDecrypt(void) { + return OPK_CONFIG_MAX_OUTPUT_SIZE_FOR_DECRYPT; +} + +bool WTPI_IsClosedPlatform(void) { return OPK_CONFIG_IS_CLOSED_PLATFORM; } + +OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { + return HDCP_NO_DIGITAL_OUTPUT; +} + +OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) { + return OPK_CONFIG_MAX_HDCP_CAPABILITY; +} + +size_t WTPI_MaxBufferSizeForGenericCrypto(void) { + return OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO; +} + +size_t WTPI_MaxSampleSize(void) { return OPK_CONFIG_MAX_SAMPLE_SIZE; } + +uint32_t WTPI_SupportedCertificates(void) { + return OPK_CONFIG_SUPPORTED_CERTIFICATES; +} + +bool WTPI_ContentDecryptBypassesTA(void) { + return OPK_CONFIG_DECRYPT_BYPASSES_TA; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h deleted file mode 100644 index 343a779..0000000 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - source code may only be used and distributed under the Widevine - License Agreement. */ - -/* The following are customizable macros we expect the TEE to implement. - These need to be in a header so the TA can use them during compilation. */ - -#ifndef OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_ -#define OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_ - -/// @addtogroup config -/// @{ - -/** - * Following should not be more than UINT32_MAX - 1. - */ -#define MAX_NUMBER_OF_SESSIONS 50 -#define MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS 20 -#define MAX_NUMBER_OF_KEYS 400 -#define CONTENT_KEYS_PER_SESSION 30 -#define ENTITLEMENT_KEYS_PER_SESSION 30 -/** This is the number of usage entries in the header. */ -#define MAX_NUMBER_OF_USAGE_ENTRIES 300 -/** The number of active entries that may be loaded simultaneously. */ -#define MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES 10 -/** The number of active DRM keys that may be loaded simultaneously. */ -#define MAX_NUMBER_OF_ASYMMETRIC_KEYS 8 -/** This is the number of key slots in the layer 2 symmetric key table. */ -#define MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES 8 - -/** - * The crypto hardware may be asked to wrap a key so that it is less vulnerable - * to attack. This is the size of a wrapped mac key. - */ -#define WRAPPED_MAC_KEY_SIZE 32 - -/** - * The extra size (in bytes) that is required by WTPI_EncryptAndSign. If - * supporting backwards-compatibility with multiple versions of WrappedData, - * this value should be as big as the version with the largest amount of - * overhead. */ -#define ENCRYPT_AND_SIGN_EXTRA 68 -/** Maximum size of a symmetric (AES) key. */ -#define MAX_SYMMETRIC_KEY_SIZE 32 -/** Maximum size of a wrapped symmetric (AES) key. This might be slightly larger - than the key itself because the crypto hardware might add verification - information to the key. */ -#define MAX_WRAPPED_SYMMETRIC_KEY_SIZE MAX_SYMMETRIC_KEY_SIZE -/** Maximum size of a wrapped asymmetric key (ECC or RSA). This might be - slightly larger than the key itself because the crypto hardware might add - verification information to the key. */ -#define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \ - (PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA) - -/// @} - -#endif /* OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c index cd15399..6f6555e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c @@ -13,8 +13,8 @@ #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_object_table.h" #include "oemcrypto_overflow.h" +#include "opk_config.h" #include "wtpi_abort_interface.h" -#include "wtpi_config_macros.h" #include "wtpi_crypto_and_key_management_interface_layer2.h" #include "wtpi_device_key_interface.h" #include "wtpi_logging_interface.h" @@ -740,3 +740,10 @@ OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { if (out == NULL || size == 0) return OEMCrypto_ERROR_INVALID_CONTEXT; return WTPI_C2_RandomBytes(out, size); } + +OEMCryptoResult WTPI_K1_PrepareExternalKeyHandle( + WTPI_K1_SymmetricKey_Handle key_handle, uint8_t* out_buffer, + size_t* out_buffer_length) { + // TODO(mattfedd): something hardware specific? + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c index 12b5bf3..313dda1 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c @@ -10,13 +10,14 @@ #include "OEMCryptoCENCCommon.h" #include "crypto_util.h" +#include "device_key_util.h" #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_object_table.h" #include "oemcrypto_overflow.h" #include "openssl/rand.h" #include "openssl/x509.h" +#include "opk_config.h" #include "wtpi_abort_interface.h" -#include "wtpi_config_macros.h" #include "wtpi_device_key_access_interface.h" #include "wtpi_device_key_interface.h" #include "wtpi_logging_interface.h" @@ -79,6 +80,7 @@ static bool IsKeyValid(uint32_t index) { case DERIVING_KEY: return key->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256; } + return false; } static bool IsKeyHandleValid(WTPI_K1_SymmetricKey_Handle key_handle) { @@ -111,40 +113,6 @@ static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle, return OEMCrypto_SUCCESS; } -static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, - SymmetricKeyType out_key_type, - uint8_t* out_key, - KeySize out_key_size) { - ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); - ABORT_IF(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256, - "Invalid key size"); - - const uint8_t* device_key = WTPI_GetDeviceKey(); - KeySize device_key_size = WTPI_GetDeviceKeySize(); - // Prepare full context for key derivation - // Server and client MAC keys must derive to the same key. - const SymmetricKeyType type_temp = - out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type; - // Cast the type into 32 bits so it is the same size as the gap left for it in - // full_context. This will be a no-op on most architectures. - const uint32_t type_32 = (uint32_t)type_temp; - // Build a full context that is unique to this starting context / key type - // combination. We start with a context template with blanks at the beginning - // and fill the blanks with the starting context and key type. - uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', - 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; - const size_t context_length = sizeof(full_context); - memcpy(full_context, &context, 4); - memcpy(full_context + 4, &type_32, 4); - const uint8_t counter = 1; - if (!OPKI_DeriveKeyWithCMAC(device_key, device_key_size, counter, - full_context, context_length, out_key_size, - out_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - static OEMCryptoResult EncryptAndSignKey(const uint8_t* key, size_t key_size, uint8_t* out, size_t out_size) { ABORT_IF(key == NULL || key_size == 0 || out == NULL, @@ -474,7 +442,7 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle( size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle) { if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 || - out_key_handle == NULL) { + out_key_handle == NULL || iv == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } if (!IsKeyHandleValid(decrypt_key_handle)) { @@ -509,7 +477,7 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( WTPI_K1_SymmetricKey_Handle* out_mac_key_client) { if (decrypt_key_handle == NULL || enc_mac_keys == NULL || enc_mac_keys_length == 0 || out_mac_key_server == NULL || - out_mac_key_client == NULL) { + out_mac_key_client == NULL || iv == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } if (!IsKeyHandleValid(decrypt_key_handle)) { @@ -661,3 +629,9 @@ OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_SUCCESS; } + +OEMCryptoResult WTPI_K1_PrepareExternalKeyHandle( + WTPI_K1_SymmetricKey_Handle key_handle, uint8_t* out_buffer, + size_t* out_buffer_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c index 1937cc6..74a676a 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c @@ -9,6 +9,7 @@ #include #include "OEMCryptoCENCCommon.h" +#include "asymmetric_key.h" #include "cose_util.h" #include "ecc_util.h" #include "oemcrypto_check_macros.h" @@ -25,14 +26,6 @@ #include "wtpi_device_key_interface.h" #include "wtpi_logging_interface.h" -typedef struct tee_asymmetric_key_handle { - AsymmetricKeyType key_type; - RSA* rsa_key; - EC_KEY* ecc_key; - // Consider to use EVP_KEY instead of serialized key. - uint8_t ed25519_key[ED25519_PRIVATE_KEY_LEN]; -} tee_asymmetric_key_handle; - // Returns true as long as one byte of ed25519_key is non-zero. static bool HasED25519Key(WTPI_AsymmetricKey_Handle key_handle) { for (size_t i = 0; i < ED25519_PRIVATE_KEY_LEN; ++i) { @@ -205,8 +198,8 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key_handle, /* This is the standard padding scheme used for license requests. */ if (padding_scheme == kSign_RSASSA_PSS) { size_t local_signature_length = *signature_length; - if (!RSASignSSAPSSSHA1(rsa, message, message_length, signature, - &local_signature_length)) { + if (!RSASignSSAPSSSHA256(rsa, message, message_length, signature, + &local_signature_length)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } *signature_length = local_signature_length; @@ -324,176 +317,32 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key_handle, return OEMCrypto_SUCCESS; } -/** - * Retrieves the device specific asymmetric key pair that is used in - * provisioning 4. This key must be unique per individual device. The key must - * be identical across reboots. - * Caller retains ownership of all parameters. - */ -static OEMCryptoResult GetDeviceAsymmetricKeyIntoHandle( - AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle* private_key_handle, - uint8_t* public_key, size_t* public_key_length) { - ABORT_IF_NULL(key_type); - ABORT_IF_NULL(private_key_handle); - ABORT_IF_NULL(public_key_length); - if (public_key == NULL || *public_key_length < ED25519_PUBLIC_KEY_LEN) { - *public_key_length = ED25519_PUBLIC_KEY_LEN; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - const uint8_t* device_key = WTPI_GetDeviceKey(); - const KeySize device_key_size = WTPI_GetDeviceKeySize(); - if (device_key == NULL || device_key_size == 0) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - const int32_t context = DEVICE_KEY_PROV40_SEED; - const uint32_t type_32 = (uint32_t)DERIVING_KEY; - // Build a full context that is unique to this starting context / key type - // combination. We start with a context template with blanks at the beginning - // and fill the blanks with the starting context and key type. - uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', - 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; - memcpy(full_context, &context, 4); - memcpy(full_context + 4, &type_32, 4); - - uint8_t seed[32]; - if (HKDF(seed, sizeof(seed), EVP_sha256(), device_key, device_key_size, - /*salt=*/NULL, /*salt_len=*/0, full_context, - sizeof(full_context)) != 1) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - uint8_t private_key_temp[ED25519_PRIVATE_KEY_LEN]; - ED25519_keypair_from_seed(public_key, private_key_temp, seed); - *public_key_length = ED25519_PUBLIC_KEY_LEN; - *key_type = PROV40_ED25519_PRIVATE_KEY; - return WTPI_CreateAsymmetricKeyHandle(private_key_temp, - sizeof(private_key_temp), *key_type, - private_key_handle); -} - -OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { - if (out_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // The |out| buffer length check is delegated to the BuildBootCertificateChain - // call below. - - AsymmetricKeyType key_type; - WTPI_AsymmetricKey_Handle private_key_handle; - uint8_t public_key[ED25519_PUBLIC_KEY_LEN]; - size_t public_key_length = sizeof(public_key); - OEMCryptoResult result = GetDeviceAsymmetricKeyIntoHandle( - &key_type, &private_key_handle, public_key, &public_key_length); - if (result != OEMCrypto_SUCCESS) return result; - // Only ED key is expected for now. - if (key_type != PROV40_ED25519_PRIVATE_KEY) { - WTPI_FreeAsymmetricKeyHandle(private_key_handle); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - result = BuildBootCertificateChain(public_key, public_key_length, key_type, - private_key_handle->ed25519_key, out, - out_length); - WTPI_FreeAsymmetricKeyHandle(private_key_handle); - return result; -} - -OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( - AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length, uint8_t* public_key, - size_t* public_key_length) { - if (key_type == NULL || wrapped_private_key_length == NULL || - public_key_length == NULL) { +OEMCryptoResult WTPI_GetSignatureHashAlgorithm( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + RETURN_INVALID_CONTEXT_IF_NULL(key); + RETURN_INVALID_CONTEXT_IF_NULL(hash_algorithm); + ABORT_IF(!IsAsymmetricKeyHandleValid(key), "Impossible key handle."); + if (key_type != key->key_type) { + LOGE("Passed-in key's type does not match passed-in key type."); return OEMCrypto_ERROR_INVALID_CONTEXT; } - // This implementation generates ECC key. An alternative is RSA key. - *key_type = DRM_ECC_PRIVATE_KEY; - // Check buffer sizes. - size_t required_wrapped_private_key_length = 0; - OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( - PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE, *key_type, - &required_wrapped_private_key_length); - if (result != OEMCrypto_SUCCESS) return result; - const size_t required_public_key_length = PKCS8_ECC_KEY_MAX_SIZE; - if (wrapped_private_key == NULL || - *wrapped_private_key_length < required_wrapped_private_key_length || - public_key == NULL || *public_key_length < required_public_key_length) { - *wrapped_private_key_length = required_wrapped_private_key_length; - *public_key_length = required_public_key_length; - return OEMCrypto_ERROR_SHORT_BUFFER; + switch (key_type) { + case DRM_RSA_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA2_256; + return OEMCrypto_SUCCESS; + + case DRM_ECC_PRIVATE_KEY: + if (GetECCKeyECDSAHashAlgorithm(key->ecc_key, hash_algorithm)) { + return OEMCrypto_SUCCESS; + } else { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + case PROV40_ED25519_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA2_512; + return OEMCrypto_SUCCESS; } - - uint8_t clear_private_key[PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE]; - size_t clear_private_key_length = sizeof(clear_private_key); - if (!NewEccKeyPair(clear_private_key, &clear_private_key_length, public_key, - public_key_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Add padding. - const uint8_t padding = - AES_BLOCK_SIZE - (clear_private_key_length % AES_BLOCK_SIZE); - memset(clear_private_key + clear_private_key_length, padding, padding); - clear_private_key_length += padding; - - size_t actual_wrapped_private_key_length = 0; - result = WTPI_GetWrappedAsymmetricKeySize(clear_private_key_length, *key_type, - &actual_wrapped_private_key_length); - if (result != OEMCrypto_SUCCESS) return result; - if (*wrapped_private_key_length < actual_wrapped_private_key_length) { - // This should not happen as we have checked buffer size. - *wrapped_private_key_length = actual_wrapped_private_key_length; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - *wrapped_private_key_length = actual_wrapped_private_key_length; - return WTPI_WrapAsymmetricKey(wrapped_private_key, - *wrapped_private_key_length, *key_type, - clear_private_key, clear_private_key_length); -} - -OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - if (message == NULL || message_length == 0 || signature_length == 0) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // The message is expected to be an EC or RSA certificate public key. - // Notice that the signature contains |message| itself. - if (message_length > 500) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - const size_t kRequiredSignatureBufferSize = 1024; - if (signature == NULL || *signature_length < kRequiredSignatureBufferSize) { - *signature_length = kRequiredSignatureBufferSize; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - AsymmetricKeyType key_type; - WTPI_AsymmetricKey_Handle private_key_handle; - uint8_t public_key_unused[ED25519_PUBLIC_KEY_LEN]; - size_t public_key_length_unused = sizeof(public_key_unused); - OEMCryptoResult result = GetDeviceAsymmetricKeyIntoHandle( - &key_type, &private_key_handle, public_key_unused, - &public_key_length_unused); - if (result != OEMCrypto_SUCCESS) return result; - // Only ED key is expected for now. - if (key_type != PROV40_ED25519_PRIVATE_KEY) { - WTPI_FreeAsymmetricKeyHandle(private_key_handle); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - size_t encoded_size = 0; - result = DiceCoseSignAndEncodeSign1( - message, message_length, private_key_handle->ed25519_key, - *signature_length, signature, &encoded_size); - WTPI_FreeAsymmetricKeyHandle(private_key_handle); - if (result != OEMCrypto_SUCCESS) return result; - - *signature_length = encoded_size; - return OEMCrypto_SUCCESS; + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c index a774bf4..c2d7408 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c @@ -12,7 +12,7 @@ #define UUID_LENGTH 16 // If changing the WrappedData struct family, make sure to update -// ENCRYPT_AND_SIGN_EXTRA in wtpi_config_macros.h if needed. +// ENCRYPT_AND_SIGN_EXTRA in opk_config.h if needed. // This struct represents a wrapped blob that we do not yet know how to // interpret. It contains only the fields that we expect every versioned blob to @@ -171,10 +171,9 @@ OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* data, return VerifyAndDecrypt_V1(context, data, data_size, out, out_size); } -OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy(const uint8_t* wrapped, - size_t wrapped_size, - const uint8_t* signature, - const uint8_t* iv, - uint8_t* out) { +OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy( + const uint8_t* wrapped UNUSED, size_t wrapped_size UNUSED, + const uint8_t* signature UNUSED, const uint8_t* iv UNUSED, + uint8_t* out UNUSED) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c index 5e57bcf..732e22c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c @@ -2,10 +2,11 @@ source code may only be used and distributed under the Widevine License Agreement. */ +#include "odk_attributes.h" #include "wtpi_idle_interface.h" -OEMCryptoResult WTPI_Idle(OEMCrypto_IdleState state, - uint32_t os_specific_code) { +OEMCryptoResult WTPI_Idle(OEMCrypto_IdleState state UNUSED, + uint32_t os_specific_code UNUSED) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c new file mode 100644 index 0000000..d53f69a --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c @@ -0,0 +1,216 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#include "wtpi_provisioning_4_interface.h" + +#include + +#include "asymmetric_key.h" +#include "cose_util.h" +#include "oemcrypto_check_macros.h" +#include "openssl/hkdf.h" +#include "wtpi_device_key_access_interface.h" +#include "wtpi_device_key_interface.h" + +#define MAX_BCC_PAYLOAD_SIZE 2048 +#define MAX_COSE_SIGN1_SIZE 2048 + +/** + * Retrieves the device specific asymmetric key pair that is used in + * provisioning 4. This key must be unique per individual device. The key must + * be identical across reboots. + * Caller retains ownership of all parameters. + */ +static OEMCryptoResult GetDeviceAsymmetricKeyIntoHandle( + AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle* private_key_handle, + uint8_t* public_key, size_t* public_key_length) { + ABORT_IF_NULL(key_type); + ABORT_IF_NULL(private_key_handle); + ABORT_IF_NULL(public_key_length); + if (public_key == NULL || *public_key_length < ED25519_PUBLIC_KEY_LEN) { + *public_key_length = ED25519_PUBLIC_KEY_LEN; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + const uint8_t* device_key = WTPI_GetDeviceKey(); + const KeySize device_key_size = WTPI_GetDeviceKeySize(); + if (device_key == NULL || device_key_size == 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + const int32_t context = DEVICE_KEY_PROV40_SEED; + const uint32_t type_32 = (uint32_t)DERIVING_KEY; + // Build a full context that is unique to this starting context / key type + // combination. We start with a context template with blanks at the beginning + // and fill the blanks with the starting context and key type. + uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', + 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; + memcpy(full_context, &context, 4); + memcpy(full_context + 4, &type_32, 4); + + uint8_t seed[32]; + if (HKDF(seed, sizeof(seed), EVP_sha256(), device_key, device_key_size, + /*salt=*/NULL, /*salt_len=*/0, full_context, + sizeof(full_context)) != 1) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + uint8_t private_key_temp[ED25519_PRIVATE_KEY_LEN]; + ED25519_keypair_from_seed(public_key, private_key_temp, seed); + *public_key_length = ED25519_PUBLIC_KEY_LEN; + *key_type = PROV40_ED25519_PRIVATE_KEY; + return WTPI_CreateAsymmetricKeyHandle(private_key_temp, + sizeof(private_key_temp), *key_type, + private_key_handle); +} + +OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // The |out| buffer length check is delegated to the BuildBootCertificateChain + // call below. + + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + uint8_t public_key[ED25519_PUBLIC_KEY_LEN]; + size_t public_key_length = sizeof(public_key); + OEMCryptoResult result = GetDeviceAsymmetricKeyIntoHandle( + &key_type, &private_key_handle, public_key, &public_key_length); + if (result != OEMCrypto_SUCCESS) return result; + // Only ED key is expected for now. + if (key_type != PROV40_ED25519_PRIVATE_KEY) { + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + result = BuildBootCertificateChain(public_key, public_key_length, key_type, + private_key_handle, out, out_length); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return result; +} + +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_BCC_PAYLOAD_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( + AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length, uint8_t* public_key, + size_t* public_key_length) { + if (key_type == NULL || wrapped_private_key_length == NULL || + public_key_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // This implementation generates ECC key. An alternative is RSA key. + *key_type = DRM_ECC_PRIVATE_KEY; + // Check buffer sizes. + size_t required_wrapped_private_key_length = 0; + OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( + PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE, *key_type, + &required_wrapped_private_key_length); + if (result != OEMCrypto_SUCCESS) return result; + const size_t required_public_key_length = PKCS8_ECC_KEY_MAX_SIZE; + if (wrapped_private_key == NULL || + *wrapped_private_key_length < required_wrapped_private_key_length || + public_key == NULL || *public_key_length < required_public_key_length) { + *wrapped_private_key_length = required_wrapped_private_key_length; + *public_key_length = required_public_key_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + uint8_t clear_private_key[PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE]; + size_t clear_private_key_length = sizeof(clear_private_key); + if (!NewEccKeyPair(clear_private_key, &clear_private_key_length, public_key, + public_key_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Add padding. + const uint8_t padding = + AES_BLOCK_SIZE - (clear_private_key_length % AES_BLOCK_SIZE); + memset(clear_private_key + clear_private_key_length, padding, padding); + clear_private_key_length += padding; + + size_t actual_wrapped_private_key_length = 0; + result = WTPI_GetWrappedAsymmetricKeySize(clear_private_key_length, *key_type, + &actual_wrapped_private_key_length); + if (result != OEMCrypto_SUCCESS) return result; + if (*wrapped_private_key_length < actual_wrapped_private_key_length) { + // This should not happen as we have checked buffer size. + *wrapped_private_key_length = actual_wrapped_private_key_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + *wrapped_private_key_length = actual_wrapped_private_key_length; + return WTPI_WrapAsymmetricKey(wrapped_private_key, + *wrapped_private_key_length, *key_type, + clear_private_key, clear_private_key_length); +} + +OEMCryptoResult WTPI_BccKeyCoseSign1(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) { + if (message == NULL || message_length == 0 || signature_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + size_t max_cose_sign1_size; + OEMCryptoResult result = WTPI_GetMaxBccKeyCoseSign1Size(&max_cose_sign1_size); + if (result != OEMCrypto_SUCCESS) return result; + // Notice that the signature contains |message| itself. + if (message_length > max_cose_sign1_size) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + const size_t kRequiredSignatureBufferSize = max_cose_sign1_size; + if (signature == NULL || *signature_length < kRequiredSignatureBufferSize) { + *signature_length = kRequiredSignatureBufferSize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + uint8_t public_key_unused[ED25519_PUBLIC_KEY_LEN]; + size_t public_key_length_unused = sizeof(public_key_unused); + result = GetDeviceAsymmetricKeyIntoHandle(&key_type, &private_key_handle, + public_key_unused, + &public_key_length_unused); + if (result != OEMCrypto_SUCCESS) return result; + // Only ED key is expected for now. + if (key_type != PROV40_ED25519_PRIVATE_KEY) { + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + size_t encoded_size = 0; + result = DiceCoseSignAndEncodeSign1(message, message_length, key_type, + private_key_handle, *signature_length, + signature, &encoded_size); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + + *signature_length = encoded_size; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetMaxBccKeyCoseSign1Size(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_COSE_SIGN1_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type, const uint8_t* message, + size_t message_size, uint8_t* signature, + size_t* signature_length) { + (void)key_type; + return ED25519Sign(key->ed25519_key, message, message_size, signature, + signature_length); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp index 54ff484..41befb8 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp @@ -4,8 +4,6 @@ { 'variables': { - # Include directory that contains wtpi_config_macros.h. - 'config_macros_header_dir%': '.', # TODO(b/207176111): add test scripts to cover both reference crypto impl 'reference_crypto_impl%': 'software', 'test_renewal%': 0, @@ -21,15 +19,6 @@ ], }, 'targets': [ - { - 'target_name': 'oemcrypto_ta_reference_cose_util', - 'sources': [ - 'cose_util.c', - ], - 'dependencies': [ - '../../../../third_party/open-dice.gyp:cbor', - ], - }, { 'target_name': 'oemcrypto_ta_reference_root_of_trust', 'sources': [ @@ -43,8 +32,8 @@ ], 'dependencies': [ '../../../odk/src/odk.gyp:odk', + 'oemcrypto_ta_reference_crypto', 'oemcrypto_ta_reference_renewal', - 'oemcrypto_ta_reference_cose_util', '../../../../third_party/open-dice.gyp:cbor', ], }, @@ -91,11 +80,14 @@ 'sources': [ 'wtpi_idle.c', ], + 'include_dirs': [ + '../../../odk/include', + ], }, { 'target_name': 'oemcrypto_ta_reference_crypto', 'include_dirs': [ - '<(config_macros_header_dir)', + '<(opk_config_dir)', '.', ], # The reference implementation of the crypto interface uses @@ -111,12 +103,14 @@ ], 'sources': [ 'crypto_util.c', + 'device_key_util.c', 'cose_util.c', 'ecc_util.c', 'rsa_util.c', 'wtpi_crc32.c', 'wtpi_crypto_asymmetric.c', 'wtpi_decrypt_sample.c', + 'wtpi_provisioning_4.c', ], 'conditions': [ ['reference_crypto_impl=="hardware"', { @@ -144,7 +138,6 @@ ], 'dependencies': [ '../../../odk/src/odk.gyp:odk', - 'oemcrypto_ta_reference_cose_util', '../../../../third_party/open-dice.gyp:cbor', ], }, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c index 258056e..59d8482 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "cose_util.h" @@ -21,6 +22,7 @@ #include "wtpi_crypto_asymmetric_interface.h" #include "wtpi_device_renewal_interface_layer1.h" #include "wtpi_logging_interface.h" +#include "wtpi_provisioning_4_interface.h" // This layer keeps a copy of the keybox in volatile memory. A more secure // implementation of this would only keep the device key in memory while it is @@ -136,7 +138,6 @@ OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input, result = OEMCrypto_ERROR_SHORT_BUFFER; goto cleanup; } - if (result != OEMCrypto_SUCCESS) goto cleanup; // Use the layer above to validate the keybox. result = WTPI_ValidateKeybox(); if (result != OEMCrypto_SUCCESS) goto cleanup; @@ -187,20 +188,44 @@ static OEMCryptoResult GetProv4DeviceID(uint8_t* device_id, return OEMCrypto_ERROR_INVALID_CONTEXT; } + size_t required_bcc_payload_size = 0; + OEMCryptoResult result = + WTPI_GetMaxBootCertificateChainSize(&required_bcc_payload_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max bcc size: %u", result); + return result; + } + // Device ID with provisioning 4 in this reference implementation is hash of // (encoded) device public key from BCC. - uint8_t bcc_buffer[1024]; // Make sure this is large enough to hold BCC. - size_t bcc_size = sizeof(bcc_buffer); - OEMCryptoResult result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); - if (result != OEMCrypto_SUCCESS) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + uint8_t* bcc_buffer = (uint8_t*)malloc(required_bcc_payload_size); + if (bcc_buffer == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + memset(bcc_buffer, 0, required_bcc_payload_size); + size_t bcc_size = required_bcc_payload_size; + result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); + if (result != OEMCrypto_SUCCESS) { + free(bcc_buffer); + return result; + } - uint8_t dk_pub_buffer[1024]; - size_t dk_pub_size = sizeof(dk_pub_buffer); + uint8_t* dk_pub_buffer = (uint8_t*)malloc(required_bcc_payload_size); + if (dk_pub_buffer == NULL) { + free(bcc_buffer); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(dk_pub_buffer, 0, required_bcc_payload_size); + size_t dk_pub_size = required_bcc_payload_size; result = GetDevicePublicKeyFromBcc(bcc_buffer, bcc_size, dk_pub_buffer, &dk_pub_size); - if (result != OEMCrypto_SUCCESS) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + free(bcc_buffer); + if (result != OEMCrypto_SUCCESS) { + free(dk_pub_buffer); + return result; + } - return WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + result = WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + free(dk_pub_buffer); + return result; } OEMCryptoResult WTPI_GetDeviceID(uint8_t* device_id, size_t device_id_length) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c index 2f3f751..da397a0 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 @@ -20,6 +20,7 @@ #include "opk_serialization_base.h" #include "shared_buffer_allocator.h" #include "tos_transport_interface.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -111,6 +112,8 @@ bool Is_Valid_OEMCryptoResult(uint32_t value) { case 2000: /* OPK_ERROR_BASE */ case 2001: /* OPK_ERROR_INCOMPATIBLE_VERSION */ case 2002: /* OPK_ERROR_NO_PERSISTENT_DATA */ + case 2003: /* OPK_ERROR_PREHOOK_FAILURE */ + case 2004: /* OPK_ERROR_POSTHOOK_FAILURE */ return true; default: return false; @@ -160,6 +163,17 @@ bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value) { } } +bool Is_Valid_OEMCrypto_TimerDelayBase(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_License_Start */ + case 1: /* OEMCrypto_License_Load */ + case 2: /* OEMCrypto_First_Decrypt */ + return true; + default: + return false; + } +} + bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value) { switch (value) { case 2011664603: /* OPK_CLEAR_INSECURE_OUTPUT_BUFFER */ @@ -170,6 +184,17 @@ bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value) { } } +bool Is_Valid_OPK_FeatureStatus(uint32_t value) { + switch (value) { + case 1764049255: /* OPK_FEATURE_NOT_SUPPORTED */ + case 2036433166: /* OPK_FEATURE_ENABLED */ + case 338164342: /* OPK_FEATURE_DISABLED */ + return true; + default: + return false; + } +} + void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring const* obj) { OPK_Pack_size_t(msg, (const size_t*)&obj->offset); @@ -365,6 +390,25 @@ void OPK_UnpackAlloc_WTPI_K1_SymmetricKey_Handle( OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, *value); } } +void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value) { + OPK_PackBoolValue(msg, value == NULL); + if (value) { + OPK_Pack_size_t(msg, value); + } +} +void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value) { + if (OPK_UnpackIsNull(msg)) { + *value = NULL; + } else { + OPK_Unpack_size_t(msg, *value); + } +} +void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value) { + *value = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t)); + if (*value) { + OPK_Unpack_size_t(msg, *value); + } +} void OPK_PackNullable_WTPI_AsymmetricKey_Handle( ODK_Message* msg, const WTPI_AsymmetricKey_Handle* value) { OPK_PackBoolValue(msg, value == NULL); @@ -407,23 +451,27 @@ void OPK_UnpackAlloc_uint32_t(ODK_Message* msg, uint32_t** value) { OPK_Unpack_uint32_t(msg, *value); } } -void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value) { +void OPK_PackNullable_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, const OEMCrypto_SignatureHashAlgorithm* value) { OPK_PackBoolValue(msg, value == NULL); if (value) { - OPK_Pack_size_t(msg, value); + OPK_Pack_OEMCrypto_SignatureHashAlgorithm(msg, value); } } -void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value) { +void OPK_UnpackNullable_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, OEMCrypto_SignatureHashAlgorithm** value) { if (OPK_UnpackIsNull(msg)) { *value = NULL; } else { - OPK_Unpack_size_t(msg, *value); + OPK_Unpack_OEMCrypto_SignatureHashAlgorithm(msg, *value); } } -void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value) { - *value = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t)); +void OPK_UnpackAlloc_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, OEMCrypto_SignatureHashAlgorithm** value) { + *value = (OEMCrypto_SignatureHashAlgorithm*)OPK_UnpackAlloc( + msg, sizeof(OEMCrypto_SignatureHashAlgorithm)); if (*value) { - OPK_Unpack_size_t(msg, *value); + OPK_Unpack_OEMCrypto_SignatureHashAlgorithm(msg, *value); } } void OPK_PackNullable_AsymmetricKeyType(ODK_Message* msg, @@ -448,3 +496,22 @@ void OPK_UnpackAlloc_AsymmetricKeyType(ODK_Message* msg, OPK_Unpack_AsymmetricKeyType(msg, *value); } } +void OPK_PackNullable_bool(ODK_Message* msg, const bool* value) { + OPK_PackBoolValue(msg, value == NULL); + if (value) { + OPK_Pack_bool(msg, value); + } +} +void OPK_UnpackNullable_bool(ODK_Message* msg, bool** value) { + if (OPK_UnpackIsNull(msg)) { + *value = NULL; + } else { + OPK_Unpack_bool(msg, *value); + } +} +void OPK_UnpackAlloc_bool(ODK_Message* msg, bool** value) { + *value = (bool*)OPK_UnpackAlloc(msg, sizeof(bool)); + if (*value) { + OPK_Unpack_bool(msg, *value); + } +} 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 1ed10d7..5b27673 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 @@ -12,6 +12,7 @@ #include "log_macros.h" #include "opk_serialization_base.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -26,7 +27,9 @@ bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value); bool Is_Valid_OEMCrypto_ProvisioningRenewalType(uint32_t value); bool Is_Valid_OEMCrypto_LicenseType(uint32_t value); bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value); +bool Is_Valid_OEMCrypto_TimerDelayBase(uint32_t value); bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value); +bool Is_Valid_OPK_FeatureStatus(uint32_t value); void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring const* obj); void OPK_Pack_OEMCrypto_DTCP2_CMI_Descriptor_0( @@ -68,6 +71,9 @@ void OPK_UnpackNullable_WTPI_K1_SymmetricKey_Handle( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value); void OPK_UnpackAlloc_WTPI_K1_SymmetricKey_Handle( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value); +void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value); +void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value); +void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value); void OPK_PackNullable_WTPI_AsymmetricKey_Handle( ODK_Message* msg, const WTPI_AsymmetricKey_Handle* value); void OPK_UnpackNullable_WTPI_AsymmetricKey_Handle( @@ -77,15 +83,21 @@ void OPK_UnpackAlloc_WTPI_AsymmetricKey_Handle( void OPK_PackNullable_uint32_t(ODK_Message* msg, const uint32_t* value); void OPK_UnpackNullable_uint32_t(ODK_Message* msg, uint32_t** value); void OPK_UnpackAlloc_uint32_t(ODK_Message* msg, uint32_t** value); -void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value); -void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value); -void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value); +void OPK_PackNullable_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, const OEMCrypto_SignatureHashAlgorithm* value); +void OPK_UnpackNullable_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, OEMCrypto_SignatureHashAlgorithm** value); +void OPK_UnpackAlloc_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* msg, OEMCrypto_SignatureHashAlgorithm** value); void OPK_PackNullable_AsymmetricKeyType(ODK_Message* msg, const AsymmetricKeyType* value); void OPK_UnpackNullable_AsymmetricKeyType(ODK_Message* msg, AsymmetricKeyType** value); void OPK_UnpackAlloc_AsymmetricKeyType(ODK_Message* msg, AsymmetricKeyType** value); +void OPK_PackNullable_bool(ODK_Message* msg, const bool* value); +void OPK_UnpackNullable_bool(ODK_Message* msg, bool** value); +void OPK_UnpackAlloc_bool(ODK_Message* msg, bool** value); #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c index d53728e..0ad4d9d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c @@ -6,6 +6,7 @@ #include "common_special_cases.h" #include "log_macros.h" +#include "odk_attributes.h" #include "opk_serialization_base.h" void OPK_Pack_WTPI_K1_SymmetricKey_Handle( @@ -98,9 +99,11 @@ void OPK_Unpack_OPK_OutputBuffer(ODK_Message* message, } void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc( - ODK_Message* message, const OEMCrypto_CENCEncryptPatternDesc* value) {} + ODK_Message* message UNUSED, + const OEMCrypto_CENCEncryptPatternDesc* value UNUSED) {} void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc( - ODK_Message* message, OEMCrypto_CENCEncryptPatternDesc* value) {} + ODK_Message* message UNUSED, + OEMCrypto_CENCEncryptPatternDesc* value UNUSED) {} void OPK_Pack_SymmetricKeyType(ODK_Message* message, const SymmetricKeyType* value) { @@ -213,3 +216,103 @@ void OPK_Unpack_OEMCrypto_Clock_Security_Level( OPK_Unpack_uint32_t(message, (uint32_t*)value); } + +void OPK_Pack_OEMCrypto_Security_Level(ODK_Message* message, + const OEMCrypto_Security_Level* 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_ProvisioningMethod( + ODK_Message* message, const OEMCrypto_ProvisioningMethod* 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) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Pack_uint32_t(message, (const uint32_t*)value); +} + +void OPK_Pack_OEMCrypto_HDCP_Capability( + ODK_Message* message, const OEMCrypto_HDCP_Capability* 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_Unpack_OEMCrypto_Security_Level(ODK_Message* message, + OEMCrypto_Security_Level* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} + +void OPK_Unpack_OEMCrypto_ProvisioningMethod( + ODK_Message* message, OEMCrypto_ProvisioningMethod* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} + +void OPK_Unpack_OEMCrypto_WatermarkingSupport( + ODK_Message* message, OEMCrypto_WatermarkingSupport* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} + +void OPK_Unpack_OEMCrypto_HDCP_Capability(ODK_Message* message, + OEMCrypto_HDCP_Capability* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} + +void OPK_Pack_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* message, const OEMCrypto_SignatureHashAlgorithm* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Pack_int(message, (const int*)value); +} + +void OPK_Unpack_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* message, OEMCrypto_SignatureHashAlgorithm* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_int(message, (int*)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 48b67a2..21301ba 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 @@ -55,4 +55,26 @@ void OPK_Pack_OEMCrypto_Clock_Security_Level( void OPK_Unpack_OEMCrypto_Clock_Security_Level( ODK_Message* msg, OEMCrypto_Clock_Security_Level* value); +void OPK_Pack_OEMCrypto_Security_Level(ODK_Message* msg, + const OEMCrypto_Security_Level* value); +void OPK_Pack_OEMCrypto_ProvisioningMethod( + ODK_Message* msg, const OEMCrypto_ProvisioningMethod* value); +void OPK_Pack_OEMCrypto_WatermarkingSupport( + ODK_Message* msg, const OEMCrypto_WatermarkingSupport* value); +void OPK_Pack_OEMCrypto_HDCP_Capability(ODK_Message* msg, + const OEMCrypto_HDCP_Capability* value); +void OPK_Unpack_OEMCrypto_Security_Level(ODK_Message* msg, + OEMCrypto_Security_Level* value); +void OPK_Unpack_OEMCrypto_ProvisioningMethod( + ODK_Message* msg, OEMCrypto_ProvisioningMethod* value); +void OPK_Unpack_OEMCrypto_WatermarkingSupport( + ODK_Message* msg, OEMCrypto_WatermarkingSupport* value); +void OPK_Unpack_OEMCrypto_HDCP_Capability(ODK_Message* msg, + OEMCrypto_HDCP_Capability* value); + +void OPK_Pack_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* message, const OEMCrypto_SignatureHashAlgorithm* value); +void OPK_Unpack_OEMCrypto_SignatureHashAlgorithm( + ODK_Message* message, OEMCrypto_SignatureHashAlgorithm* value); + #endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp new file mode 100644 index 0000000..aae843a --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp @@ -0,0 +1,176 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "cose_util.h" +#include "dice/cbor_reader.h" +#include "log.h" + +using wtpi_test::ScopedCbor; + +OEMCryptoResult GetCoseSign1OffsetInBcc(uint8_t* bytes, size_t bytes_len, + size_t* offset, size_t* len) { + if (!bytes || bytes_len == 0 || !offset || !len) + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + + struct CborIn in; + CborInInit(bytes, bytes_len, &in); + size_t bcc_item_count = 0; + enum CborReadResult res = CborReadArray(&in, &bcc_item_count); + if (res != CBOR_READ_RESULT_OK) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (bcc_item_count < 2) { + // There should at least be the public key and one entry. + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // The first item in the BCC array is the device public key + res = CborReadSkip(&in); + if (res != CBOR_READ_RESULT_OK) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + const size_t cosesign_offset = CborInOffset(&in); + // Skip the item to know the size + res = CborReadSkip(&in); + if (res != CBOR_READ_RESULT_OK) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + size_t data_size = CborInOffset(&in) - cosesign_offset; + *offset = cosesign_offset; + *len = data_size; + return OEMCrypto_SUCCESS; +} + +void print_cbor(cn_cbor* cn, uint32_t type) { + if (!cn) return; + + cn_cbor_errback error; + cn_cbor* e; + ScopedCbor c; + switch (type) { + case CN_CBOR_BYTES: + LOGE("bytes with length %zu", cn->length); + c = ScopedCbor(cn_cbor_decode(cn->v.bytes, cn->length, &error)); + e = c.get(); + if (!e) { + LOGE("decoded bytes returned nil with error %d at pos %zu", error.err, + error.pos); + return; + } + print_cbor(e, e->type); + break; + case CN_CBOR_ARRAY: + for (size_t i = 0; i < cn->length; i++) { + e = cn_cbor_index(cn, i); + LOGE("element #%zu:", i); + LOGE("type: %d", e->type); + print_cbor(e, e->type); + } + break; + case CN_CBOR_MAP: + e = cn; + for (cn_cbor* cp = e->first_child; cp && cp->next; cp = cp->next->next) { + if (cp->type == CN_CBOR_UINT) { + LOGE("cp->v.uint %lu", cp->v.uint); + } else if (cp->type == CN_CBOR_INT) { + LOGE("cp->v.sint %ld", cp->v.sint); + } else { + LOGE("tag type is %d", cp->type); + } + } + break; + default: + LOGE("processing other type: %d", type); + } +} + +namespace wtpi_test { +// Copied and modified from open-dice test_utils.cc +ScopedCbor ExtractCwtFromCborCertificate(const uint8_t* certificate, + size_t certificate_size) { + // BCC structure is something like + /* + * ARRAY[ + * MAP{ <-- DK_pub + * tag 1 + * ... + * }, + * ARRAY[ <-- CoseSign1 + * BYTES-MAP{ + * }, + * MAP{ + * }, + * BYTES-MAP{ <-- CWT, aka "BCC payload" + * tag -4670552 <-- public key + * tag -4670553 + * }, + * BYTES{ <-- signature + * }, + * ... + * + */ + + if (!certificate) return nullptr; + cn_cbor_errback error; + ScopedCbor bcc(cn_cbor_decode(certificate, certificate_size, &error)); + if (!bcc) { + return nullptr; + } + + // print tree of current bcc struct for debugging. May have to inspect error + // if cn_cbor_decode() fails. + // print_cbor(bcc.get(), bcc->type); + + if (bcc->type != CN_CBOR_ARRAY || bcc->length < 2) { + return nullptr; + } + + cn_cbor* inner_arr = cn_cbor_index(bcc.get(), 1); + if (!inner_arr || inner_arr->type != CN_CBOR_ARRAY || inner_arr->length < 4) { + return nullptr; + } + + cn_cbor* payload = cn_cbor_index(inner_arr, 2); + if (!payload || payload->type != CN_CBOR_BYTES) { + return nullptr; + } + + ScopedCbor cwt(cn_cbor_decode(payload->v.bytes, payload->length, &error)); + if (cwt && cwt->type != CN_CBOR_MAP) { + return nullptr; + } + return cwt; +} + +// Copied from open-dice test_utils.cc +ScopedCbor ExtractPublicKeyFromCwt(const cn_cbor* cwt) { + cn_cbor_errback error; + cn_cbor* key_bytes = cn_cbor_mapget_int(cwt, -4670552); + if (!key_bytes || key_bytes->type != CN_CBOR_BYTES) { + return nullptr; + } + ScopedCbor key(cn_cbor_decode(key_bytes->v.bytes, key_bytes->length, &error)); + if (key && key->type != CN_CBOR_MAP) { + return nullptr; + } + return key; +} + +ScopedCbor ExtractPublicKeyFromBcc(const uint8_t* bytes, size_t bytes_len) { + // Get bcc payload, which is a CBOR Web Token. + ScopedCbor cwt = ExtractCwtFromCborCertificate(bytes, bytes_len); + if (!cwt) { + return nullptr; + } + + // Extract public key from CWT struct + ScopedCbor public_key_cbor = ExtractPublicKeyFromCwt(cwt.get()); + if (!public_key_cbor) { + return nullptr; + } + + return public_key_cbor; +} +} // namespace wtpi_test diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.h new file mode 100644 index 0000000..63593df --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.h @@ -0,0 +1,36 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#ifndef WTPI_TEST_COSE_UTIL_H_ +#define WTPI_TEST_COSE_UTIL_H_ + +#include +#include + +#include "OEMCryptoCENC.h" +#include "cose/cose.h" + +namespace wtpi_test { +// A scoped pointer for cn_cbor. +struct CborDeleter { + void operator()(cn_cbor* c) { cn_cbor_free(c); } +}; + +using ScopedCbor = std::unique_ptr; + +// Given BCC data in |bytes| and |bytes_len|, return a unique ptr to a cn_cbor +// struct of type CN_CBOR_BYTE that contains the public key. Must be a cn_cbor +// pointer to be compatible with COSE-C library's COSE_Sign1_validate() func +ScopedCbor ExtractPublicKeyFromBcc(const uint8_t* bytes, size_t bytes_len); +} // namespace wtpi_test + +// Print basic type and tag information for a cn_cbor* tree for array, map, and +// byte CBOR types +void print_cbor(cn_cbor* cn, uint32_t type); + +// Given BCC data in |bytes| and |bytes_len|, find the byte offset of the +// CoseSign1 entry and return that. Also return the length of the entry. +OEMCryptoResult GetCoseSign1OffsetInBcc(uint8_t* bytes, size_t bytes_len, + size_t* offset, size_t* len); +#endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp index 2327a08..6cc11e8 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp @@ -2,9 +2,8 @@ // source code may only be used and distributed under the Widevine License // Agreement. -#include - #include "OEMCryptoCENC.h" +#include "cose_util.h" #include "log.h" #include "oemcrypto_key_types.h" #include "openssl/curve25519.h" @@ -12,7 +11,10 @@ #include "openssl/sha.h" #include "opk_init.h" #include "ssl_util.h" +#include "string_conversions.h" +#include "test_common.h" #include "tos_shared_memory_interface.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -27,17 +29,6 @@ using wtpi_test::EcKeyPtr; using wtpi_test::MakeEccPublicKey; using wtpi_test::NewEccPrivateKey; using wtpi_test::SerializeEccPrivateKey; -using wtpi_test::SerializeEccPublicKey; -// -// Pre-define some types to help with key clean up. -using WtpiAsymmetircKeyType = - std::remove_pointer::type; -const auto wtpi_asymmetric_key_free = [](WtpiAsymmetircKeyType* key) { - WTPI_FreeAsymmetricKeyHandle(key); -}; -using WtpiAsymmetircKeyPtr = - std::unique_ptr>; class CryptoTest : public ::testing::Test { protected: @@ -160,12 +151,9 @@ TEST_F(CryptoTest, AESCBCEncryptFailsForBadInput) { WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 15, iv.data(), output.data())); - // TODO(b/205751866): serializer allocates iv array on TEE side regardless if - // REE iv ptr is NULL, so the NULL never propagates to the TEE - // - // ASSERT_EQ( - // OEMCrypto_ERROR_INVALID_CONTEXT, - // WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, NULL, output.data())); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, NULL, output.data())); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, @@ -267,12 +255,9 @@ TEST_F(CryptoTest, AESCBCDecryptFailsForBadInput) { WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 15, iv.data(), output.data())); - // TODO(b/205751866): serializer allocates iv array on TEE side regardless if - // REE iv ptr is NULL, so the NULL never propagates to the TEE - // - // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - // WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16, NULL, - // output.data())); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16, + NULL, output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16, @@ -473,156 +458,158 @@ TEST_F(CryptoTest, HMAC_SHA256FailsWithBadInput) { WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), NULL)); } -TEST_F(CryptoTest, HMAC_SHA256Basic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +// Values passed to test suites represent indices of hmac_test_cases[] +class HmacTest : public CryptoTest, public testing::WithParamInterface {}; + +// Copied and slightly modified from RFC 4231 +static struct hmac_sha256_test_case { + std::string key; + std::string data; + std::string expected; +} const hmac_sha256_test_cases[] = { + { + // 128-bit key, modified from RFC 4231 test case 2 + .key = "4a656665000000000000000000000000", + .data = "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + .expected = "5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843", + }, + { + // 256-bit key, modified from RFC 4231 test case 1 + .key = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b000000000000000000000" + "000", + .data = "4869205468657265", + .expected = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c" + "2e32cff7", + }, +}; + +// Copied and slightly modified from RFC 2202 +static struct hmac_sha1_test_case { + std::string key; + std::string data; + std::string expected; +} const hmac_sha1_test_cases[] = { + { + // 128-bit key, modified from RFC 2202 test case 1 + .key = "4a656665000000000000000000000000", + .data = "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + .expected = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + }, + { + // 256-bit key, original test + .key = + "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + .data = "4869205468657265", + .expected = "B5A023B7CAC1A26C9139B9C2136EA3C3FAC5D349", + }, +}; + +INSTANTIATE_TEST_SUITE_P(HmacTests, HmacTest, testing::Values(0, 1)); + +TEST_P(HmacTest, HMAC_SHA256Basic) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(32, 0); - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), - output.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA256(key_handle, data.data(), + data.size(), output.data())); - std::vector expected = {232, 73, 155, 228, 241, 152, 13, 104, - 241, 50, 34, 164, 24, 223, 92, 189, - 151, 213, 63, 221, 245, 144, 194, 16, - 142, 34, 212, 0, 5, 183, 7, 19}; - for (int i = 0; i < 32; i++) { - ASSERT_EQ(expected[i], output[i]); - } + EXPECT_EQ(expected, output); } -TEST_F(CryptoTest, HMAC_SHA256_VerifyBasic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA256_VerifyBasic) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } - std::vector signature = {232, 73, 155, 228, 241, 152, 13, 104, - 241, 50, 34, 164, 24, 223, 92, 189, - 151, 213, 63, 221, 245, 144, 194, 16, - 142, 34, 212, 0, 5, 183, 7, 19}; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 32, - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), + expected.data())); - signature[0] = 0xFF; + expected[0] = 0xFF; ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(), - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), + expected.data())); } -TEST_F(CryptoTest, HMAC_SHA256_VerifyFailsWithBadInput) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA256_VerifyFailsWithBadInput) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } - std::vector signature = {70, 189, 50, 6, 5, 197, 166, 182, - 22, 58, 183, 11, 198, 52, 91, 146, - 165, 249, 8, 231, 159, 229, 137, 121, - 194, 62, 187, 71, 209, 165, 227, 7}; - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(NULL, input.data(), input.size(), - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(NULL, data.data(), data.size(), + expected.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, NULL, input.size(), - signature.data())); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 0, - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, NULL, data.size(), + expected.data())); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), 0, expected.data())); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(), NULL)); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), NULL)); } -TEST_F(CryptoTest, HMAC_SHA1Basic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA1Basic) { + struct hmac_sha1_test_case const* t = &hmac_sha1_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(20, 0); - ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(key_handle, input.data(), - input.size(), output.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(key_handle, data.data(), + data.size(), output.data())); - std::vector expected = {106, 229, 208, 106, 97, 2, 39, - 252, 78, 167, 85, 132, 70, 103, - 130, 238, 157, 20, 201, 141}; - for (int i = 0; i < 20; i++) { - ASSERT_EQ(expected[i], output[i]); - } + ASSERT_EQ(expected, output); } -TEST_F(CryptoTest, HMAC_SHA1FailsWithBadInput) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA1FailsWithBadInput) { + struct hmac_sha1_test_case const* t = &hmac_sha1_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(20, 0); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(NULL, input.data(), input.size(), output.data())); + WTPI_C1_HMAC_SHA1(NULL, data.data(), data.size(), output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, NULL, input.size(), output.data())); + WTPI_C1_HMAC_SHA1(key_handle, NULL, data.size(), output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, input.data(), 0, output.data())); + WTPI_C1_HMAC_SHA1(key_handle, data.data(), 0, output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, input.data(), input.size(), NULL)); + WTPI_C1_HMAC_SHA1(key_handle, data.data(), data.size(), NULL)); } TEST_F(CryptoTest, CopyToOutputBufferBasicInsecure) { @@ -772,6 +759,15 @@ TEST_F(CryptoTest, RSASign) { std::string message = "Hello world"; std::vector input(message.begin(), message.end()); + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1; + ASSERT_EQ(WTPI_GetSignatureHashAlgorithm(handle, DRM_RSA_PRIVATE_KEY, + &hash_algorithm), + OEMCrypto_SUCCESS); + const EVP_MD* digest = nullptr; + ASSERT_TRUE(OecHashAlgorithmToOpenSslMd(hash_algorithm, &digest)) + << "Unable to interpret algorithm reported by " + "WTPI_GetSignatureHashAlgorithm()"; + std::vector output(256, 0); size_t output_len = 256; ASSERT_EQ(OEMCrypto_SUCCESS, @@ -787,7 +783,7 @@ TEST_F(CryptoTest, RSASign) { ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), rsa)); EXPECT_TRUE(VerifyPSSSignature(pkey.get(), input.data(), input.size(), - output.data(), output.size())) + output.data(), output.size(), digest)) << "PSS signature check failed."; } @@ -971,8 +967,8 @@ TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks) { WTPI_K1_CreateKeyHandle(expected_derived_key, KEY_SIZE_256, MAC_KEY_CLIENT, &expected_derived_key_handle)); - // perform an operation with out_key_handle and expected_derived_key_handle to - // prove they are using the same underlying key data + // perform an operation with out_key_handle and expected_derived_key_handle + // to prove they are using the same underlying key data std::vector input; for (int i = 0; i < 32; i++) { input.push_back(i); @@ -992,6 +988,56 @@ TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks) { } } +TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks256BitDerivingKey) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, DERIVING_KEY, + &key_handle)); + + const uint8_t context[4] = {'T', 'E', 'S', 'T'}; + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_DeriveKeyFromKeyHandle(key_handle, 1, context, + sizeof(context), ENCRYPTION_KEY, + KEY_SIZE_128, &out_key_handle)); + + const uint8_t expected_derived_key[] = {124, 186, 187, 120, 87, 47, + 248, 173, 91, 134, 226, 18, + 145, 223, 106, 64}; + + WTPI_K1_SymmetricKey_Handle expected_derived_key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(expected_derived_key, KEY_SIZE_128, + ENCRYPTION_KEY, &expected_derived_key_handle)); + + // perform an operation with out_key_handle and expected_derived_key_handle + // to prove they are using the same underlying key data + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + std::vector output1(20, 1); + std::vector output2(20, 2); + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(out_key_handle, input.data(), + input.size(), output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA1(expected_derived_key_handle, input.data(), + input.size(), output2.data())); + + for (int i = 0; i < 20; i++) { + ASSERT_EQ(output1[i], output2[i]); + } +} + TEST_F(CryptoTest, WrapKeyFailsForBadInputs) { std::vector key; for (int i = 0; i < 32; i++) { @@ -1082,10 +1128,10 @@ TEST_F(CryptoTest, WrapAndUnwrapKeyWorks) { } TEST_F(CryptoTest, WrapAsymmetricKeyFailsForBadInputs) { - uint8_t output[4000]; + uint8_t output[4000] = {0}; size_t output_length = 4000; AsymmetricKeyType key_type = DRM_RSA_PRIVATE_KEY; - uint8_t clear_key[256]; + uint8_t clear_key[256] = {0}; size_t clear_key_length = 256; ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, @@ -1233,13 +1279,10 @@ TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleFailsForBadInput) { decrypt_key_handle, enc_key.data(), 7, iv.data(), MAC_KEY_CLIENT, &out_key_handle)); - // TODO(b/205751866): serializer allocates iv array on TEE side regardless if - // REE iv ptr is NULL, so the NULL never propagates to the TEE - // - // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - // WTPI_K1_AESDecryptAndCreateKeyHandle( - // decrypt_key_handle, enc_key.data(), enc_key.size(), NULL, - // MAC_KEY_CLIENT, &out_key_handle)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandle( + decrypt_key_handle, enc_key.data(), enc_key.size(), NULL, + MAC_KEY_CLIENT, &out_key_handle)); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_K1_AESDecryptAndCreateKeyHandle( @@ -1344,13 +1387,10 @@ TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleForMacKeysFailsForBadInput) { decryption_key_handle, enc_mac_keys.data(), 63, iv.data(), &out_mac_key_server, &out_mac_key_client)); - // TODO(b/205751866): serializer allocates iv array on TEE side regardless - // if REE iv ptr is NULL, so the NULL never propagates to the TEE - // - // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - // WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( - // decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), NULL, - // &out_mac_key_server, &out_mac_key_client)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), + NULL, &out_mac_key_server, &out_mac_key_client)); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( @@ -1546,6 +1586,9 @@ TEST_F(CryptoTest, WTPI_EncryptAndSign_Then_VerifyAndDecrypt_Works) { } TEST_F(CryptoTest, ECCSignFailsForBadInput) { + if ((WTPI_SupportedCertificates() & OEMCrypto_Supports_ECC_secp256r1) == 0) { + GTEST_SKIP() << "Skipping ECC test because ECC operation not supported"; + } EcKeyPtr ec_key; ASSERT_TRUE(NewEccPrivateKey(&ec_key)); std::vector serialized_key; @@ -1573,6 +1616,9 @@ TEST_F(CryptoTest, ECCSignFailsForBadInput) { } TEST_F(CryptoTest, ECCLoadKeyAndSign) { + if ((WTPI_SupportedCertificates() & OEMCrypto_Supports_ECC_secp256r1) == 0) { + GTEST_SKIP() << "Skipping ECC test because ECC operation not supported"; + } EcKeyPtr ec_key; ASSERT_TRUE(NewEccPrivateKey(&ec_key)); std::vector serialized_key; @@ -1612,298 +1658,3 @@ TEST_F(CryptoTest, ECCLoadKeyAndSign) { ASSERT_EQ(WTPI_FreeAsymmetricKeyHandle(key_handle), OEMCrypto_SUCCESS); } - -TEST_F(CryptoTest, ECCDeriveSessionKeySuccess) { - // Create device private key. - EcKeyPtr device_priv_key; - ASSERT_TRUE(NewEccPrivateKey(&device_priv_key)); - std::vector serialized_key; - ASSERT_TRUE(SerializeEccPrivateKey(device_priv_key.get(), &serialized_key)); - WTPI_AsymmetricKey_Handle key_handle; - OEMCryptoResult result = WTPI_CreateAsymmetricKeyHandle( - serialized_key.data(), serialized_key.size(), DRM_ECC_PRIVATE_KEY, - &key_handle); - ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load device ECC key"; - // Assign to smart pointer for auto cleanup on failure. - WtpiAsymmetircKeyPtr device_key_handle(key_handle, wtpi_asymmetric_key_free); - key_handle = nullptr; - - // Serialize device public key (view from server). - std::vector device_pub_key_data; - ASSERT_TRUE( - SerializeEccPublicKey(device_priv_key.get(), &device_pub_key_data)); - device_priv_key.reset(); - - // Create server private key. - EcKeyPtr server_priv_key; - ASSERT_TRUE(NewEccPrivateKey(&server_priv_key)); - ASSERT_TRUE(SerializeEccPrivateKey(server_priv_key.get(), &serialized_key)); - result = WTPI_CreateAsymmetricKeyHandle(serialized_key.data(), - serialized_key.size(), - DRM_ECC_PRIVATE_KEY, &key_handle); - ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load server ECC key"; - WtpiAsymmetircKeyPtr server_key_handle(key_handle, wtpi_asymmetric_key_free); - key_handle = nullptr; - - // Serialize server public key (view from device). - std::vector server_pub_key_data; - ASSERT_TRUE( - SerializeEccPublicKey(server_priv_key.get(), &server_pub_key_data)); - server_priv_key.reset(); - - // Perform key exchange on device. - size_t session_key_size = 0; - result = WTPI_ECCDeriveSessionKey( - device_key_handle.get(), server_pub_key_data.data(), - server_pub_key_data.size(), - /* session_key = */ nullptr, &session_key_size); - ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER) - << "Expected session key size to be returned"; - ASSERT_EQ(session_key_size, KEY_SIZE_256); - std::vector device_session_key(session_key_size, 0); - result = WTPI_ECCDeriveSessionKey( - device_key_handle.get(), server_pub_key_data.data(), - server_pub_key_data.size(), device_session_key.data(), &session_key_size); - ASSERT_EQ(result, OEMCrypto_SUCCESS) - << "Failed to derive session key on device"; - - // Perform key exchange on server. - std::vector server_session_key(session_key_size); - result = WTPI_ECCDeriveSessionKey( - server_key_handle.get(), device_pub_key_data.data(), - device_pub_key_data.size(), server_session_key.data(), &session_key_size); - ASSERT_EQ(result, OEMCrypto_SUCCESS) - << "Failed to derive session key on server"; - - ASSERT_EQ(device_session_key, server_session_key) - << "Mismatch between server and device session key"; -} - -TEST_F(CryptoTest, ECCDeriveSessionKeyFailsForBadInput) { - // Create device private key. - EcKeyPtr device_priv_key; - ASSERT_TRUE(NewEccPrivateKey(&device_priv_key)); - std::vector serialized_key; - ASSERT_TRUE(SerializeEccPrivateKey(device_priv_key.get(), &serialized_key)); - WTPI_AsymmetricKey_Handle key_handle; - OEMCryptoResult result = WTPI_CreateAsymmetricKeyHandle( - serialized_key.data(), serialized_key.size(), DRM_ECC_PRIVATE_KEY, - &key_handle); - ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load device ECC key"; - // Assign to smart pointer for auto cleanup on failure. - WtpiAsymmetircKeyPtr device_key_handle(key_handle, wtpi_asymmetric_key_free); - key_handle = nullptr; - - // Serialize device public key (view from server). - std::vector device_pub_key_data; - ASSERT_TRUE( - SerializeEccPublicKey(device_priv_key.get(), &device_pub_key_data)); - device_priv_key.reset(); - - // Create server private key. - EcKeyPtr server_priv_key; - ASSERT_TRUE(NewEccPrivateKey(&server_priv_key)); - ASSERT_TRUE(SerializeEccPrivateKey(server_priv_key.get(), &serialized_key)); - result = WTPI_CreateAsymmetricKeyHandle(serialized_key.data(), - serialized_key.size(), - DRM_ECC_PRIVATE_KEY, &key_handle); - ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load server ECC key"; - WtpiAsymmetircKeyPtr server_key_handle(key_handle, wtpi_asymmetric_key_free); - key_handle = nullptr; - - // Serialize server public key (view from device). - size_t session_key_size = KEY_SIZE_256; - std::vector server_pub_key_data; - ASSERT_TRUE( - SerializeEccPublicKey(server_priv_key.get(), &server_pub_key_data)); - server_priv_key.reset(); - - std::vector device_session_key(session_key_size, 0); - ASSERT_EQ(WTPI_ECCDeriveSessionKey( - NULL, server_pub_key_data.data(), server_pub_key_data.size(), - device_session_key.data(), &session_key_size), - OEMCrypto_ERROR_INVALID_CONTEXT); - ASSERT_EQ(WTPI_ECCDeriveSessionKey( - device_key_handle.get(), NULL, server_pub_key_data.size(), - device_session_key.data(), &session_key_size), - OEMCrypto_ERROR_INVALID_CONTEXT); - ASSERT_EQ(WTPI_ECCDeriveSessionKey(device_key_handle.get(), - server_pub_key_data.data(), 0, - device_session_key.data(), NULL), - OEMCrypto_ERROR_INVALID_CONTEXT); - - size_t bad_size = 0; - ASSERT_EQ(WTPI_ECCDeriveSessionKey(device_key_handle.get(), - server_pub_key_data.data(), - server_pub_key_data.size(), - device_session_key.data(), &bad_size), - OEMCrypto_ERROR_SHORT_BUFFER); - EXPECT_GT(bad_size, size_t(0)); - - ASSERT_EQ(WTPI_ECCDeriveSessionKey( - device_key_handle.get(), server_pub_key_data.data(), - server_pub_key_data.size(), NULL, &session_key_size), - OEMCrypto_ERROR_SHORT_BUFFER); -} - -TEST_F(CryptoTest, GetBootCertificateChainSuccess) { - const size_t kExpectedBccSize = 180; - std::vector buffer; - buffer.resize(kExpectedBccSize); - size_t buffer_size = buffer.size(); - - OEMCryptoResult result = - WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); - - if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) { - GTEST_SKIP() << "BCC not supported"; - } - ASSERT_EQ(result, OEMCrypto_SUCCESS); - EXPECT_EQ(buffer_size, kExpectedBccSize); -} - -TEST_F(CryptoTest, GenerateRandomCertificateKeyPairSuccess) { - const size_t kBufferSize = 2000; - AsymmetricKeyType type; - uint8_t public_key[kBufferSize]; - size_t public_key_length = sizeof(public_key); - uint8_t wrapped_private_key[kBufferSize]; - size_t wrapped_private_key_length = sizeof(wrapped_private_key); - - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( - &type, wrapped_private_key, &wrapped_private_key_length, - public_key, &public_key_length), - OEMCrypto_SUCCESS); - EXPECT_TRUE(type == DRM_ECC_PRIVATE_KEY || type == DRM_RSA_PRIVATE_KEY); - EXPECT_GT(public_key_length, size_t(0)); - EXPECT_LT(public_key_length, kBufferSize); - EXPECT_GT(wrapped_private_key_length, size_t(0)); - EXPECT_LT(wrapped_private_key_length, kBufferSize); - - // Unwrap private key into key handle, use it to sign a message, then verify - // it with public key to ensure keypair is valid - WTPI_AsymmetricKey_Handle key_handle; - uint32_t allowed_schemes; - ASSERT_EQ(WTPI_UnwrapIntoAsymmetricKeyHandle(wrapped_private_key, - wrapped_private_key_length, type, - &key_handle, &allowed_schemes), - OEMCrypto_SUCCESS); - - size_t signature_size = 0; - ASSERT_EQ(WTPI_GetSignatureSize(key_handle, &signature_size), - OEMCrypto_SUCCESS); - const uint8_t kMessage[] = {'m', 'e', 's', 's', 'a', 'g', 'e'}; - std::vector signature(signature_size, 0); - - switch (type) { - case DRM_RSA_PRIVATE_KEY: { - // sign - ASSERT_EQ( - WTPI_RSASign(key_handle, kMessage, sizeof(kMessage), signature.data(), - &signature_size, RSA_Padding_Scheme(allowed_schemes)), - OEMCrypto_SUCCESS); - - signature.resize(signature_size); - - // Verify with generated public key - boringssl_ptr pkey(EVP_PKEY_new()); - const uint8_t* pos = public_key; - RSA* decoded_rsa = d2i_RSA_PUBKEY(NULL, &pos, public_key_length); - ASSERT_NE(nullptr, decoded_rsa) << "RSA pub key failed to decode"; - ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), decoded_rsa)); - - EXPECT_TRUE(VerifyPSSSignature(pkey.get(), kMessage, sizeof(kMessage), - signature.data(), signature_size)) - << "PSS signature check failed."; - ASSERT_EQ(WTPI_FreeAsymmetricKeyHandle(key_handle), OEMCrypto_SUCCESS); - } break; - case DRM_ECC_PRIVATE_KEY: { - // sign - ASSERT_EQ(WTPI_ECCSign(key_handle, kMessage, sizeof(kMessage), - signature.data(), &signature_size), - OEMCrypto_SUCCESS); - signature.resize(signature_size); - - // Verify with generated public key - EcKeyPtr ec_pub_key; - const uint8_t* pos = public_key; - EC_KEY* decoded_pub_key = d2i_EC_PUBKEY(NULL, &pos, public_key_length); - ASSERT_NE(nullptr, decoded_pub_key) << "ECC pub key failed to decode"; - ec_pub_key.reset(decoded_pub_key); - - uint8_t digest[SHA256_DIGEST_LENGTH]; - ASSERT_NE(SHA256(kMessage, sizeof(kMessage), digest), nullptr); - constexpr int kDefaultEcdsaType = 0; // Specific to OpenSSL. - constexpr int kSignatureValid = 1; - ASSERT_EQ( - ECDSA_verify(kDefaultEcdsaType, digest, SHA256_DIGEST_LENGTH, - signature.data(), static_cast(signature.size()), - ec_pub_key.get()), - kSignatureValid) - << "Signature verification failed"; - ASSERT_EQ(WTPI_FreeAsymmetricKeyHandle(key_handle), OEMCrypto_SUCCESS); - } break; - case PROV40_ED25519_PRIVATE_KEY: - default: - FAIL() << "Unsupported key type"; - break; - } -} - -TEST_F(CryptoTest, GenerateRandomCertificateKeyPairFailsForBadInput) { - const size_t kBufferSize = 1000; - AsymmetricKeyType type; - uint8_t public_key[kBufferSize]; - size_t public_key_length = sizeof(public_key); - uint8_t wrapped_private_key[kBufferSize]; - size_t wrapped_private_key_length = sizeof(wrapped_private_key); - - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( - NULL, wrapped_private_key, &wrapped_private_key_length, - public_key, &public_key_length), - OEMCrypto_ERROR_INVALID_CONTEXT); - - ASSERT_EQ( - WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, NULL, - public_key, &public_key_length), - OEMCrypto_ERROR_INVALID_CONTEXT); - - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, - &wrapped_private_key_length, - public_key, NULL), - OEMCrypto_ERROR_INVALID_CONTEXT); - - size_t bad_size = 0; - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, - &bad_size, public_key, - &public_key_length), - OEMCrypto_ERROR_SHORT_BUFFER); - EXPECT_GT(bad_size, size_t(0)); - - bad_size = 0; - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, - &wrapped_private_key_length, - public_key, &bad_size), - OEMCrypto_ERROR_SHORT_BUFFER); - EXPECT_GT(bad_size, size_t(0)); - - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( - &type, NULL, &wrapped_private_key_length, public_key, - &public_key_length), - OEMCrypto_ERROR_SHORT_BUFFER); - - ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, - &wrapped_private_key_length, - NULL, &public_key_length), - OEMCrypto_ERROR_SHORT_BUFFER); -} - -TEST_F(CryptoTest, WTPI_DeviceKeyCoseSign1Success) { - const uint8_t message[3] = {'m', 's', 'g'}; - uint8_t signature_buffer[1024]; - size_t signature_buffer_size = sizeof(signature_buffer); - - ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), signature_buffer, - &signature_buffer_size), - OEMCrypto_SUCCESS); -} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/provisioning_4_interface_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/provisioning_4_interface_test.cpp new file mode 100644 index 0000000..f68f1dd --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/provisioning_4_interface_test.cpp @@ -0,0 +1,477 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "OEMCryptoCENC.h" +#include "cose_util.h" +#include "log.h" +#include "openssl/curve25519.h" +#include "openssl/ecdsa.h" +#include "opk_init.h" +#include "ssl_util.h" +#include "test_common.h" +#include "wtpi_config_interface.h" +#include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_provisioning_4_interface.h" + +using wtpi_test::EcKeyPtr; +using wtpi_test::ExtractPublicKeyFromBcc; +using wtpi_test::NewEccPrivateKey; +using wtpi_test::ScopedCbor; +using wtpi_test::SerializeEccPrivateKey; +using wtpi_test::SerializeEccPublicKey; + +class Prov4Test : public ::testing::Test { + protected: + Prov4Test() {} + + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + ASSERT_EQ(true, OPK_Initialize()); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + if (WTPI_GetProvisioningMethod() != OEMCrypto_BootCertificateChain) { + GTEST_SKIP() + << "Skipping Provisioning 4 WTPI tests since " + "provisioning method is not OEMCrypto_BootCertificateChain"; + } + } + + void TearDown() override { + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); + OPK_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(Prov4Test, ECCDeriveSessionKeySuccess) { + // Create device private key. + EcKeyPtr device_priv_key; + ASSERT_TRUE(NewEccPrivateKey(&device_priv_key)); + std::vector serialized_key; + ASSERT_TRUE(SerializeEccPrivateKey(device_priv_key.get(), &serialized_key)); + WTPI_AsymmetricKey_Handle key_handle; + OEMCryptoResult result = WTPI_CreateAsymmetricKeyHandle( + serialized_key.data(), serialized_key.size(), DRM_ECC_PRIVATE_KEY, + &key_handle); + ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load device ECC key"; + // Assign to smart pointer for auto cleanup on failure. + WtpiAsymmetricKeyPtr device_key_handle(key_handle, wtpi_asymmetric_key_free); + key_handle = nullptr; + + // Serialize device public key (view from server). + std::vector device_pub_key_data; + ASSERT_TRUE( + SerializeEccPublicKey(device_priv_key.get(), &device_pub_key_data)); + device_priv_key.reset(); + + // Create server private key. + EcKeyPtr server_priv_key; + ASSERT_TRUE(NewEccPrivateKey(&server_priv_key)); + ASSERT_TRUE(SerializeEccPrivateKey(server_priv_key.get(), &serialized_key)); + result = WTPI_CreateAsymmetricKeyHandle(serialized_key.data(), + serialized_key.size(), + DRM_ECC_PRIVATE_KEY, &key_handle); + ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load server ECC key"; + WtpiAsymmetricKeyPtr server_key_handle(key_handle, wtpi_asymmetric_key_free); + key_handle = nullptr; + + // Serialize server public key (view from device). + std::vector server_pub_key_data; + ASSERT_TRUE( + SerializeEccPublicKey(server_priv_key.get(), &server_pub_key_data)); + server_priv_key.reset(); + + // Perform key exchange on device. + size_t session_key_size = 0; + result = WTPI_ECCDeriveSessionKey( + device_key_handle.get(), server_pub_key_data.data(), + server_pub_key_data.size(), + /* session_key = */ nullptr, &session_key_size); + ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER) + << "Expected session key size to be returned"; + ASSERT_EQ(session_key_size, KEY_SIZE_256); + std::vector device_session_key(session_key_size, 0); + result = WTPI_ECCDeriveSessionKey( + device_key_handle.get(), server_pub_key_data.data(), + server_pub_key_data.size(), device_session_key.data(), &session_key_size); + ASSERT_EQ(result, OEMCrypto_SUCCESS) + << "Failed to derive session key on device"; + + // Perform key exchange on server. + std::vector server_session_key(session_key_size); + result = WTPI_ECCDeriveSessionKey( + server_key_handle.get(), device_pub_key_data.data(), + device_pub_key_data.size(), server_session_key.data(), &session_key_size); + ASSERT_EQ(result, OEMCrypto_SUCCESS) + << "Failed to derive session key on server"; + + ASSERT_EQ(device_session_key, server_session_key) + << "Mismatch between server and device session key"; +} + +TEST_F(Prov4Test, ECCDeriveSessionKeyFailsForBadInput) { + // Create device private key. + EcKeyPtr device_priv_key; + ASSERT_TRUE(NewEccPrivateKey(&device_priv_key)); + std::vector serialized_key; + ASSERT_TRUE(SerializeEccPrivateKey(device_priv_key.get(), &serialized_key)); + WTPI_AsymmetricKey_Handle key_handle; + OEMCryptoResult result = WTPI_CreateAsymmetricKeyHandle( + serialized_key.data(), serialized_key.size(), DRM_ECC_PRIVATE_KEY, + &key_handle); + ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load device ECC key"; + // Assign to smart pointer for auto cleanup on failure. + WtpiAsymmetricKeyPtr device_key_handle(key_handle, wtpi_asymmetric_key_free); + key_handle = nullptr; + + // Serialize device public key (view from server). + std::vector device_pub_key_data; + ASSERT_TRUE( + SerializeEccPublicKey(device_priv_key.get(), &device_pub_key_data)); + device_priv_key.reset(); + + // Create server private key. + EcKeyPtr server_priv_key; + ASSERT_TRUE(NewEccPrivateKey(&server_priv_key)); + ASSERT_TRUE(SerializeEccPrivateKey(server_priv_key.get(), &serialized_key)); + result = WTPI_CreateAsymmetricKeyHandle(serialized_key.data(), + serialized_key.size(), + DRM_ECC_PRIVATE_KEY, &key_handle); + ASSERT_EQ(result, OEMCrypto_SUCCESS) << "Failed to load server ECC key"; + WtpiAsymmetricKeyPtr server_key_handle(key_handle, wtpi_asymmetric_key_free); + key_handle = nullptr; + + // Serialize server public key (view from device). + size_t session_key_size = KEY_SIZE_256; + std::vector server_pub_key_data; + ASSERT_TRUE( + SerializeEccPublicKey(server_priv_key.get(), &server_pub_key_data)); + server_priv_key.reset(); + + std::vector device_session_key(session_key_size, 0); + ASSERT_EQ(WTPI_ECCDeriveSessionKey( + NULL, server_pub_key_data.data(), server_pub_key_data.size(), + device_session_key.data(), &session_key_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + ASSERT_EQ(WTPI_ECCDeriveSessionKey( + device_key_handle.get(), NULL, server_pub_key_data.size(), + device_session_key.data(), &session_key_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + ASSERT_EQ(WTPI_ECCDeriveSessionKey(device_key_handle.get(), + server_pub_key_data.data(), 0, + device_session_key.data(), NULL), + OEMCrypto_ERROR_INVALID_CONTEXT); + + size_t bad_size = 0; + ASSERT_EQ(WTPI_ECCDeriveSessionKey(device_key_handle.get(), + server_pub_key_data.data(), + server_pub_key_data.size(), + device_session_key.data(), &bad_size), + OEMCrypto_ERROR_SHORT_BUFFER); + EXPECT_GT(bad_size, size_t(0)); + + ASSERT_EQ(WTPI_ECCDeriveSessionKey( + device_key_handle.get(), server_pub_key_data.data(), + server_pub_key_data.size(), NULL, &session_key_size), + OEMCrypto_ERROR_SHORT_BUFFER); +} + +TEST_F(Prov4Test, GetBootCertificateChainSuccess) { + std::vector buffer(0); + size_t buffer_size = 0; + + OEMCryptoResult res = + WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + EXPECT_EQ(res, OEMCrypto_ERROR_SHORT_BUFFER); + buffer.resize(buffer_size); + + res = WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + + ASSERT_EQ(res, OEMCrypto_SUCCESS); + + // Get public key to validate CoseSign1 signature + ScopedCbor public_key_cbor = + ExtractPublicKeyFromBcc(buffer.data(), buffer_size); + ASSERT_NE(public_key_cbor, nullptr); + + size_t offset = 0; + size_t len = 0; + res = GetCoseSign1OffsetInBcc(buffer.data(), buffer_size, &offset, &len); + ASSERT_EQ(OEMCrypto_SUCCESS, res); + + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = (HCOSE_SIGN1)COSE_Decode( + buffer.data() + offset, len, &struct_type, COSE_sign1_object, &error); + ASSERT_NE(sign1, nullptr); + + bool result = COSE_Sign1_validate(sign1, public_key_cbor.get(), &error); + COSE_Sign1_Free(sign1); + ASSERT_TRUE(result); +} + +TEST_F(Prov4Test, UseBootCertificateChainToValidateCoseSign1) { + std::vector buffer(0); + size_t buffer_size = 0; + + OEMCryptoResult res = + WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + EXPECT_EQ(res, OEMCrypto_ERROR_SHORT_BUFFER); + buffer.resize(buffer_size); + + res = WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + ASSERT_EQ(res, OEMCrypto_SUCCESS); + + // Validate twice to verify that WTPI_BccKeyCoseSign1() is + // deterministically using the same private key to sign, and the BCC pub key + // is still usable to verify + for (int i = 0; i < 2; i++) { + const uint8_t message[3] = {'m', 's', 'g'}; + std::vector cosesign1(0); + size_t cosesign1_len = 0; + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, sizeof(message), cosesign1.data(), + &cosesign1_len), + OEMCrypto_ERROR_SHORT_BUFFER); + cosesign1.resize(cosesign1_len); + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, sizeof(message), cosesign1.data(), + &cosesign1_len), + OEMCrypto_SUCCESS); + + // Get public key to validate CoseSign1 signature + ScopedCbor public_key_cbor = + ExtractPublicKeyFromBcc(buffer.data(), buffer_size); + ASSERT_NE(public_key_cbor, nullptr); + + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = + (HCOSE_SIGN1)COSE_Decode(cosesign1.data(), cosesign1_len, &struct_type, + COSE_sign1_object, &error); + ASSERT_NE(sign1, nullptr); + + bool result = COSE_Sign1_validate(sign1, public_key_cbor.get(), &error); + COSE_Sign1_Free(sign1); + ASSERT_TRUE(result); + } +} + +TEST_F(Prov4Test, GenerateRandomCertificateKeyPairSuccess) { + const size_t kBufferSize = 2000; + AsymmetricKeyType type; + std::vector public_key; + size_t public_key_length = 0; + uint8_t wrapped_private_key[kBufferSize]; + size_t wrapped_private_key_length = sizeof(wrapped_private_key); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( + &type, wrapped_private_key, &wrapped_private_key_length, + public_key.data(), &public_key_length), + OEMCrypto_ERROR_SHORT_BUFFER); + public_key.resize(public_key_length); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( + &type, wrapped_private_key, &wrapped_private_key_length, + public_key.data(), &public_key_length), + OEMCrypto_SUCCESS); + + EXPECT_TRUE(type == DRM_ECC_PRIVATE_KEY || type == DRM_RSA_PRIVATE_KEY); + EXPECT_GT(public_key_length, size_t(0)); + EXPECT_LT(public_key_length, kBufferSize); + EXPECT_GT(wrapped_private_key_length, 0u); + EXPECT_LT(wrapped_private_key_length, kBufferSize); + + // Unwrap private key into key handle, use it to sign a message, then verify + // it with public key to ensure keypair is valid + WTPI_AsymmetricKey_Handle key_handle; + uint32_t allowed_schemes; + ASSERT_EQ(WTPI_UnwrapIntoAsymmetricKeyHandle(wrapped_private_key, + wrapped_private_key_length, type, + &key_handle, &allowed_schemes), + OEMCrypto_SUCCESS); + + size_t signature_size = 0; + ASSERT_EQ(WTPI_GetSignatureSize(key_handle, &signature_size), + OEMCrypto_SUCCESS); + const uint8_t kMessage[] = {'m', 'e', 's', 's', 'a', 'g', 'e'}; + std::vector signature(signature_size, 0); + + switch (type) { + case DRM_RSA_PRIVATE_KEY: { + // Get digest algorithm + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1; + ASSERT_EQ( + WTPI_GetSignatureHashAlgorithm(key_handle, type, &hash_algorithm), + OEMCrypto_SUCCESS); + const EVP_MD* digest = nullptr; + ASSERT_TRUE(OecHashAlgorithmToOpenSslMd(hash_algorithm, &digest)) + << "Unable to interpret algorithm reported by " + "WTPI_GetSignatureHashAlgorithm()"; + + // sign + ASSERT_EQ( + WTPI_RSASign(key_handle, kMessage, sizeof(kMessage), signature.data(), + &signature_size, RSA_Padding_Scheme(allowed_schemes)), + OEMCrypto_SUCCESS); + + signature.resize(signature_size); + + // Verify with generated public key + boringssl_ptr pkey(EVP_PKEY_new()); + const uint8_t* pos = public_key.data(); + RSA* decoded_rsa = d2i_RSA_PUBKEY(NULL, &pos, public_key_length); + ASSERT_NE(nullptr, decoded_rsa) << "RSA pub key failed to decode"; + ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), decoded_rsa)); + + EXPECT_TRUE(VerifyPSSSignature(pkey.get(), kMessage, sizeof(kMessage), + signature.data(), signature_size, digest)) + << "PSS signature check failed."; + ASSERT_EQ(WTPI_FreeAsymmetricKeyHandle(key_handle), OEMCrypto_SUCCESS); + } break; + case DRM_ECC_PRIVATE_KEY: { + // sign + ASSERT_EQ(WTPI_ECCSign(key_handle, kMessage, sizeof(kMessage), + signature.data(), &signature_size), + OEMCrypto_SUCCESS); + signature.resize(signature_size); + + // Verify with generated public key + EcKeyPtr ec_pub_key; + const uint8_t* pos = public_key.data(); + EC_KEY* decoded_pub_key = d2i_EC_PUBKEY(NULL, &pos, public_key_length); + ASSERT_NE(nullptr, decoded_pub_key) << "ECC pub key failed to decode"; + ec_pub_key.reset(decoded_pub_key); + + uint8_t digest[SHA256_DIGEST_LENGTH]; + ASSERT_NE(SHA256(kMessage, sizeof(kMessage), digest), nullptr); + constexpr int kDefaultEcdsaType = 0; // Specific to OpenSSL. + constexpr int kSignatureValid = 1; + ASSERT_EQ( + ECDSA_verify(kDefaultEcdsaType, digest, SHA256_DIGEST_LENGTH, + signature.data(), static_cast(signature.size()), + ec_pub_key.get()), + kSignatureValid) + << "Signature verification failed"; + ASSERT_EQ(WTPI_FreeAsymmetricKeyHandle(key_handle), OEMCrypto_SUCCESS); + } break; + case PROV40_ED25519_PRIVATE_KEY: + default: + FAIL() << "Unsupported key type"; + break; + } +} + +TEST_F(Prov4Test, GenerateRandomCertificateKeyPairFailsForBadInput) { + const size_t kBufferSize = 1000; + AsymmetricKeyType type; + uint8_t public_key[kBufferSize]; + size_t public_key_length = sizeof(public_key); + uint8_t wrapped_private_key[kBufferSize]; + size_t wrapped_private_key_length = sizeof(wrapped_private_key); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( + NULL, wrapped_private_key, &wrapped_private_key_length, + public_key, &public_key_length), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ( + WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, NULL, + public_key, &public_key_length), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, + &wrapped_private_key_length, + public_key, NULL), + OEMCrypto_ERROR_INVALID_CONTEXT); + + size_t bad_size = 0; + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, + &bad_size, public_key, + &public_key_length), + OEMCrypto_ERROR_SHORT_BUFFER); + EXPECT_GT(bad_size, size_t(0)); + + bad_size = 0; + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, + &wrapped_private_key_length, + public_key, &bad_size), + OEMCrypto_ERROR_SHORT_BUFFER); + EXPECT_GT(bad_size, size_t(0)); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( + &type, NULL, &wrapped_private_key_length, public_key, + &public_key_length), + OEMCrypto_ERROR_SHORT_BUFFER); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair(&type, wrapped_private_key, + &wrapped_private_key_length, + NULL, &public_key_length), + OEMCrypto_ERROR_SHORT_BUFFER); +} + +TEST_F(Prov4Test, WTPI_BccKeyCoseSign1Success) { + const uint8_t message[3] = {'m', 's', 'g'}; + std::vector signature_buffer(0); + size_t signature_buffer_size = 0; + ASSERT_EQ( + WTPI_BccKeyCoseSign1(message, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_SHORT_BUFFER); + signature_buffer.resize(signature_buffer_size); + ASSERT_EQ( + WTPI_BccKeyCoseSign1(message, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_SUCCESS); + + // Use the COSE-C library to decode and validate as a COSE_sign1 struct + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = + (HCOSE_SIGN1)COSE_Decode(signature_buffer.data(), signature_buffer_size, + &struct_type, COSE_sign1_object, &error); + if (!sign1) { + FAIL() << "COSE_Decode failed"; + } + // Cannot validate signature because we cannot access the public key. + // A separate test uses the BCC to validate WTPI_BccKeyCoseSign1() +} + +TEST_F(Prov4Test, WTPI_BccKeyCoseSign1FailsForBadInput) { + const uint8_t message[3] = {'m', 's', 'g'}; + std::vector signature_buffer(0); + size_t signature_buffer_size = 0; + + ASSERT_EQ(WTPI_BccKeyCoseSign1(NULL, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, 0, signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, sizeof(message), NULL, + &signature_buffer_size), + OEMCrypto_ERROR_SHORT_BUFFER); + + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, sizeof(message), + signature_buffer.data(), NULL), + OEMCrypto_ERROR_INVALID_CONTEXT); + + size_t bad_size = 0; + ASSERT_EQ(WTPI_BccKeyCoseSign1(message, sizeof(message), + signature_buffer.data(), &bad_size), + OEMCrypto_ERROR_SHORT_BUFFER); + ASSERT_GT(bad_size, size_t(0)); + + size_t max_message_length; + ASSERT_EQ(WTPI_GetMaxBccKeyCoseSign1Size(&max_message_length), + OEMCrypto_SUCCESS); + size_t bad_message_length = max_message_length + 1; + ASSERT_EQ( + WTPI_BccKeyCoseSign1(message, bad_message_length, signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_BUFFER_TOO_LARGE); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c index 362d118..f2109aa 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 @@ -22,6 +22,7 @@ #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" #include "tos_transport_interface.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -32,10 +33,15 @@ OEMCryptoResult WTPI_PrepareGenerationNumber(void) { 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_PrepareGenerationNumber_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -59,10 +65,15 @@ OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { 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_LoadGenerationNumber_Request(value); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -86,10 +97,15 @@ OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { 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_SaveGenerationNumber_Request(value); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -114,10 +130,15 @@ OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle, 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_K1_GetKeySize_Request(key_handle, size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -145,11 +166,16 @@ OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_SymmetricKey_Handle key_handle, 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_C1_AESCBCDecrypt_Request(key_handle, key_length, in_buffer, in_buffer_length, iv, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -177,11 +203,16 @@ OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle, 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_C1_AESCBCEncrypt_Request(key_handle, in_buffer, in_buffer_length, iv, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -208,11 +239,16 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key_handle, 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_C1_HMAC_SHA1_Request(key_handle, input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -237,10 +273,15 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length, 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_C1_SHA256_Request(input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -266,11 +307,16 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle, 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_C1_HMAC_SHA256_Request(key_handle, input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -296,11 +342,16 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify( 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_C1_HMAC_SHA256_Verify_Request(key_handle, input, input_length, signature); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -327,11 +378,16 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer(const uint8_t* input, 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_C1_CopyToOutputBuffer_Request(input, input_length, out, output_offset); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -355,10 +411,15 @@ OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t out_length) { 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_C1_RandomBytes_Request(out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -382,10 +443,15 @@ OEMCryptoResult WTPI_K1_InitializeKeyManagement(void) { 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_K1_InitializeKeyManagement_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -409,10 +475,15 @@ OEMCryptoResult WTPI_K1_TerminateKeyManagement(void) { 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_K1_TerminateKeyManagement_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -438,11 +509,16 @@ OEMCryptoResult WTPI_K1_CreateKeyHandle( 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_K1_CreateKeyHandle_Request(input, input_length, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -468,11 +544,16 @@ OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( 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_K1_DeriveDeviceKeyIntoHandle_Request( context, out_key_type, out_key_handle, out_key_size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -500,12 +581,17 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle( 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_K1_AESDecryptAndCreateKeyHandle_Request( decrypt_key_handle, enc_key, enc_key_length, iv, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -534,12 +620,17 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( 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_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( decrypt_key_handle, enc_mac_keys, enc_mac_keys_length, iv, out_mac_key_server, out_mac_key_client); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -568,12 +659,17 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( 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_K1_DeriveKeyFromKeyHandle_Request( key_handle, counter, context, context_length, out_key_type, out_key_size, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -601,11 +697,16 @@ OEMCryptoResult WTPI_K1_WrapKey(uint32_t context, 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_K1_WrapKey_Request(context, key_handle, key_type, wrapped_key, wrapped_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -632,11 +733,16 @@ OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( 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_K1_UnwrapIntoKeyHandle_Request( context, wrapped_key, wrapped_key_length, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -661,10 +767,15 @@ OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) { 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_K1_FreeKeyHandle_Request(key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -683,6 +794,42 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_K1_PrepareExternalKeyHandle( + WTPI_K1_SymmetricKey_Handle key_handle, uint8_t* out_buffer, + size_t* out_buffer_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_K1_PrepareExternalKeyHandle_Request(key_handle, out_buffer, + out_buffer_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_K1_PrepareExternalKeyHandle_Response( + &response, &result, &out_buffer, &out_buffer_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_CreateAsymmetricKeyHandle( const uint8_t* input, size_t input_length, AsymmetricKeyType key_type, WTPI_AsymmetricKey_Handle* key_handle) { @@ -690,11 +837,16 @@ OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( 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_CreateAsymmetricKeyHandle_Request(input, input_length, key_type, key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -721,11 +873,16 @@ OEMCryptoResult WTPI_UnwrapIntoAsymmetricKeyHandle( 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_UnwrapIntoAsymmetricKeyHandle_Request( input, input_length, key_type, key_handle, allowed_schemes); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -751,10 +908,15 @@ OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( 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_FreeAsymmetricKeyHandle_Request(key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -780,11 +942,16 @@ OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(size_t enc_private_key_length, 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_GetWrappedAsymmetricKeySize_Request(enc_private_key_length, key_type, buffer_size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -812,11 +979,16 @@ OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, 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_WrapAsymmetricKey_Request(output, output_length, key_type, clear_key, clear_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -844,11 +1016,16 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, 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_RSASign_Request(key, message, message_length, signature, signature_length, padding_scheme); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -875,11 +1052,16 @@ OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key, 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_RSADecrypt_Request(key, input, input_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -905,11 +1087,16 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, 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_ECCSign_Request(key, message, message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -938,11 +1125,16 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, 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_ECCDeriveSessionKey_Request( key, key_source, key_source_length, session_key, session_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -968,10 +1160,15 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, 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_GetSignatureSize_Request(key, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -990,15 +1187,56 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_GetSignatureHashAlgorithm( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + 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_GetSignatureHashAlgorithm_Request(key, key_type, hash_algorithm); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetSignatureHashAlgorithm_Response(&response, &result, + &hash_algorithm); + + 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_GetBootCertificateChain(uint8_t* out, 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_GetBootCertificateChain_Request(out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1018,6 +1256,39 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_GetMaxBootCertificateChainSize_Request(out_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetMaxBootCertificateChainSize_Response(&response, &result, + &out_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, uint8_t* public_key, @@ -1026,12 +1297,17 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( 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_GenerateRandomCertificateKeyPair_Request( key_type, wrapped_private_key, wrapped_private_key_length, public_key, public_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1052,24 +1328,198 @@ cleanup_and_return: return result; } -OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { +OEMCryptoResult WTPI_GetSignedCsrPayload(const uint8_t* challenge, + size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_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_DeviceKeyCoseSign1_Request(message, message_length, - signature, signature_length); + request = OPK_Pack_GetSignedCsrPayload_Request( + challenge, challenge_length, encoded_device_info, + encoded_device_info_length, signed_csr_payload, + signed_csr_payload_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); - OPK_Unpack_DeviceKeyCoseSign1_Response(&response, &result, &signature, - &signature_length); + OPK_Unpack_GetSignedCsrPayload_Response( + &response, &result, &signed_csr_payload, &signed_csr_payload_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; +} + +size_t WTPI_MaxDeviceInfoSize(void) { + pthread_mutex_lock(&api_lock); + size_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxDeviceInfoSize_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxDeviceInfoSize_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCryptoResult WTPI_GetDeviceInformation(uint8_t* out, 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_GetDeviceInformation_Request(out, out_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetDeviceInformation_Response(&response, &result, &out, + &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_BccKeyCoseSign1(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_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_BccKeyCoseSign1_Request(message, message_length, signature, + signature_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_BccKeyCoseSign1_Response(&response, &result, &signature, + &signature_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_GetMaxBccKeyCoseSign1Size(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_GetMaxBccKeyCoseSign1Size_Request(out_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetMaxBccKeyCoseSign1Size_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_GetDeviceFusedStatus(bool* is_fused) { + 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_GetDeviceFusedStatus_Request(is_fused); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetDeviceFusedStatus_Response(&response, &result, &is_fused); if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1089,10 +1539,15 @@ OEMCryptoResult WTPI_Crc32Init(uint32_t* initial_hash) { 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_Crc32Init_Request(initial_hash); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1117,10 +1572,15 @@ OEMCryptoResult WTPI_Crc32Cont(const uint8_t* in, size_t in_length, 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_Crc32Cont_Request(in, in_length, prev_crc, new_crc); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1147,11 +1607,16 @@ OEMCryptoResult WTPI_Crc32Cont_OutputBuffer(const OPK_OutputBuffer* in, 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_Crc32Cont_OutputBuffer_Request(in, in_offset, in_length, prev_crc, new_crc); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1175,10 +1640,15 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { 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_GetTrustedTime_Request(time_in_s); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1202,10 +1672,15 @@ OEMCryptoResult WTPI_InitializeClock(void) { 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_InitializeClock_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1229,10 +1704,15 @@ OEMCryptoResult WTPI_TerminateClock(void) { 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_TerminateClock_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1256,10 +1736,15 @@ OEMCrypto_Clock_Security_Level WTPI_GetClockType(void) { OEMCrypto_Clock_Security_Level result = kInsecureClock; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_GetClockType_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1277,17 +1762,768 @@ cleanup_and_return: return result; } +OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_Security_Level result = OEMCrypto_Level_Unknown; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_GetSecurityLevel_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetSecurityLevel_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_ProvisioningMethod result = OEMCrypto_ProvisioningError; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_GetProvisioningMethod_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetProvisioningMethod_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +uint32_t WTPI_GetResourceRatingTier(void) { + pthread_mutex_lock(&api_lock); + uint32_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_GetResourceRatingTier_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetResourceRatingTier_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OPK_FeatureStatus WTPI_IsTAAntiRollbackEnabled(void) { + pthread_mutex_lock(&api_lock); + OPK_FeatureStatus result = OPK_FEATURE_NOT_SUPPORTED; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsTAAntiRollbackEnabled_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsTAAntiRollbackEnabled_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_IsProductionReady(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsProductionReady_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsProductionReady_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCrypto_WatermarkingSupport WTPI_GetWatermarkingSupport(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_WatermarkingSupport result = OEMCrypto_WatermarkingNotSupported; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_GetWatermarkingSupport_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetWatermarkingSupport_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) { + 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_GetCurrentSRMVersion_Request(srm_version); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetCurrentSRMVersion_Response(&response, &result, &srm_version); + + 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; +} + +bool WTPI_IsAntiRollbackHWPresent(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsAntiRollbackHWPresent_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsAntiRollbackHWPresent_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field) { + 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_ApplyCGMS_Request(cgms_field); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_ApplyCGMS_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_IsCGMS_AActive(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsCGMS_AActive_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsCGMS_AActive_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_SupportsCGMS_A(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_SupportsCGMS_A_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_SupportsCGMS_A_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_HasAnalogDisplay(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_HasAnalogDisplay_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_HasAnalogDisplay_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_IsAnalogDisplayActive(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsAnalogDisplayActive_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsAnalogDisplayActive_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_CanDisableAnalogDisplay(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_CanDisableAnalogDisplay_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_CanDisableAnalogDisplay_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_DisableAnalogDisplay(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_DisableAnalogDisplay_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_DisableAnalogDisplay_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +size_t WTPI_MaxBufferSizeForDecrypt(void) { + pthread_mutex_lock(&api_lock); + size_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxBufferSizeForDecrypt_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxBufferSizeForDecrypt_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +size_t WTPI_MaxOutputSizeForDecrypt(void) { + pthread_mutex_lock(&api_lock); + size_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxOutputSizeForDecrypt_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxOutputSizeForDecrypt_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_IsClosedPlatform(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_IsClosedPlatform_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_IsClosedPlatform_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_HDCP_Capability result = HDCP_NONE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_CurrentHDCPCapability_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_CurrentHDCPCapability_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_HDCP_Capability result = HDCP_NONE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxHDCPCapability_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxHDCPCapability_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +size_t WTPI_MaxBufferSizeForGenericCrypto(void) { + pthread_mutex_lock(&api_lock); + size_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxBufferSizeForGenericCrypto_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxBufferSizeForGenericCrypto_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +size_t WTPI_MaxSampleSize(void) { + pthread_mutex_lock(&api_lock); + size_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_MaxSampleSize_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_MaxSampleSize_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +uint32_t WTPI_SupportedCertificates(void) { + pthread_mutex_lock(&api_lock); + uint32_t result = 0; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_SupportedCertificates_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_SupportedCertificates_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + +bool WTPI_ContentDecryptBypassesTA(void) { + pthread_mutex_lock(&api_lock); + bool result = false; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_ContentDecryptBypassesTA_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_ContentDecryptBypassesTA_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCryptoResult WTPI_GetEncryptAndSignSize(uint32_t context, size_t in_length, size_t* wrapped_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_GetEncryptAndSignSize_Request(context, in_length, wrapped_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1314,11 +2550,16 @@ OEMCryptoResult WTPI_EncryptAndSign(uint32_t context, const uint8_t* data, 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_EncryptAndSign_Request(context, data, data_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1344,11 +2585,16 @@ OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* wrapped, 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_VerifyAndDecrypt_Request(context, wrapped, wrapped_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1376,11 +2622,16 @@ OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy(const uint8_t* wrapped, 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_VerifyAndDecryptUsageData_Legacy_Request( wrapped, wrapped_length, signature, iv, out); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c index 7d36e31..a8fa099 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 @@ -22,6 +22,7 @@ #include "ree_special_cases.h" #include "shared_buffer_allocator.h" #include "tos_transport_interface.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -161,7 +162,7 @@ ODK_Message OPK_Pack_C1_AESCBCDecrypt_Request( OPK_Pack_size_t(&msg, &key_length); OPK_PackMemory(&msg, (const uint8_t*)in_buffer, OPK_ToLengthType(in_buffer_length)); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_PackAlloc(&msg, out_buffer); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); @@ -207,7 +208,7 @@ ODK_Message OPK_Pack_C1_AESCBCEncrypt_Request( OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &key_handle); OPK_PackMemory(&msg, (const uint8_t*)in_buffer, OPK_ToLengthType(in_buffer_length)); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_PackAlloc(&msg, out_buffer); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); @@ -474,7 +475,7 @@ ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Request( OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &decrypt_key_handle); OPK_PackMemory(&msg, (const uint8_t*)enc_key, OPK_ToLengthType(enc_key_length)); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_Pack_SymmetricKeyType(&msg, &key_type); OPK_PackIsNull(&msg, out_key_handle); OPK_PackEOM(&msg); @@ -515,7 +516,7 @@ ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &decrypt_key_handle); OPK_PackMemory(&msg, (const uint8_t*)enc_mac_keys, OPK_ToLengthType(enc_mac_keys_length)); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_PackIsNull(&msg, out_mac_key_server); OPK_PackIsNull(&msg, out_mac_key_client); OPK_PackEOM(&msg); @@ -701,10 +702,52 @@ void OPK_Unpack_K1_FreeKeyHandle_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_K1_PrepareExternalKeyHandle_Request( + WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* out_buffer, + const size_t* out_buffer_length) { + uint32_t api_value = 10022; /* from _tee10022 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackNullable_size_t(&msg, out_buffer_length); + OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &key_handle); + OPK_PackAlloc(&msg, out_buffer); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_K1_PrepareExternalKeyHandle_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** out_buffer, + size_t** out_buffer_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10022) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, out_buffer_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(out_buffer_length)); + if (p && *out_buffer) { + memcpy(*out_buffer, p, OPK_SafeDerefSizeTPtrPtr(out_buffer_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Request( const uint8_t* input, size_t input_length, AsymmetricKeyType key_type, const WTPI_AsymmetricKey_Handle* key_handle) { - uint32_t api_value = 10022; /* from _tee10022 */ + uint32_t api_value = 10023; /* from _tee10023 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -723,7 +766,7 @@ void OPK_Unpack_CreateAsymmetricKeyHandle_Response( WTPI_AsymmetricKey_Handle** key_handle) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10022) + if (api_value != 10023) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -741,7 +784,7 @@ ODK_Message OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Request( const uint8_t* input, size_t input_length, AsymmetricKeyType key_type, const WTPI_AsymmetricKey_Handle* key_handle, const uint32_t* allowed_schemes) { - uint32_t api_value = 10023; /* from _tee10023 */ + uint32_t api_value = 10024; /* from _tee10024 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -761,7 +804,7 @@ void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Response( WTPI_AsymmetricKey_Handle** key_handle, uint32_t** allowed_schemes) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10023) + if (api_value != 10024) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -778,7 +821,7 @@ void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Response( ODK_Message OPK_Pack_FreeAsymmetricKeyHandle_Request( WTPI_AsymmetricKey_Handle key_handle) { - uint32_t api_value = 10024; /* from _tee10024 */ + uint32_t api_value = 10025; /* from _tee10025 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -793,7 +836,7 @@ void OPK_Unpack_FreeAsymmetricKeyHandle_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10024) + if (api_value != 10025) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -809,7 +852,7 @@ void OPK_Unpack_FreeAsymmetricKeyHandle_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Request( size_t enc_private_key_length, AsymmetricKeyType key_type, const size_t* buffer_size) { - uint32_t api_value = 10025; /* from _tee10025 */ + uint32_t api_value = 10026; /* from _tee10026 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -827,7 +870,7 @@ void OPK_Unpack_GetWrappedAsymmetricKeySize_Response(ODK_Message* msg, size_t** buffer_size) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10025) + if (api_value != 10026) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -846,7 +889,7 @@ ODK_Message OPK_Pack_WrapAsymmetricKey_Request(const uint8_t* output, AsymmetricKeyType key_type, const uint8_t* clear_key, size_t clear_key_length) { - uint32_t api_value = 10026; /* from _tee10026 */ + uint32_t api_value = 10027; /* from _tee10027 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -868,7 +911,7 @@ void OPK_Unpack_WrapAsymmetricKey_Response(ODK_Message* msg, size_t* output_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10026) + if (api_value != 10027) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, output_length); OPK_Unpack_uint32_t(msg, result); @@ -895,7 +938,7 @@ ODK_Message OPK_Pack_RSASign_Request(WTPI_AsymmetricKey_Handle key, const uint8_t* signature, const size_t* signature_length, RSA_Padding_Scheme padding_scheme) { - uint32_t api_value = 10027; /* from _tee10027 */ + uint32_t api_value = 10028; /* from _tee10028 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -917,7 +960,7 @@ void OPK_Unpack_RSASign_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10027) + if (api_value != 10028) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -942,7 +985,7 @@ ODK_Message OPK_Pack_RSADecrypt_Request(WTPI_AsymmetricKey_Handle key, const uint8_t* input, size_t input_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10028; /* from _tee10028 */ + uint32_t api_value = 10029; /* from _tee10029 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -961,7 +1004,7 @@ void OPK_Unpack_RSADecrypt_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10028) + if (api_value != 10029) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -987,7 +1030,7 @@ ODK_Message OPK_Pack_ECCSign_Request(WTPI_AsymmetricKey_Handle key, size_t message_length, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10029; /* from _tee10029 */ + uint32_t api_value = 10030; /* from _tee10030 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1008,7 +1051,7 @@ void OPK_Unpack_ECCSign_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10029) + if (api_value != 10030) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -1033,7 +1076,7 @@ ODK_Message OPK_Pack_ECCDeriveSessionKey_Request( WTPI_AsymmetricKey_Handle key, const uint8_t* key_source, size_t key_source_length, const uint8_t* session_key, const size_t* session_key_length) { - uint32_t api_value = 10030; /* from _tee10030 */ + uint32_t api_value = 10031; /* from _tee10031 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1055,7 +1098,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Response(ODK_Message* msg, size_t** session_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10030) + if (api_value != 10031) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, session_key_length); OPK_Unpack_uint32_t(msg, result); @@ -1078,7 +1121,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetSignatureSize_Request(WTPI_AsymmetricKey_Handle key, const size_t* signature_length) { - uint32_t api_value = 10031; /* from _tee10031 */ + uint32_t api_value = 10032; /* from _tee10032 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1095,7 +1138,7 @@ void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10031) + if (api_value != 10032) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1109,9 +1152,44 @@ void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Request( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + const OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + uint32_t api_value = 10033; /* from _tee10033 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_WTPI_AsymmetricKey_Handle(&msg, &key); + OPK_Pack_AsymmetricKeyType(&msg, &key_type); + OPK_PackIsNull(&msg, hash_algorithm); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetSignatureHashAlgorithm_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SignatureHashAlgorithm** hash_algorithm) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10033) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_OEMCrypto_SignatureHashAlgorithm(msg, hash_algorithm); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_GetBootCertificateChain_Request(const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10032; /* from _tee10032 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1129,7 +1207,7 @@ void OPK_Unpack_GetBootCertificateChain_Response(ODK_Message* msg, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10032) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -1150,11 +1228,43 @@ void OPK_Unpack_GetBootCertificateChain_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Request( + const size_t* out_length) { + uint32_t api_value = 10035; /* from _tee10035 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetMaxBootCertificateChainSize_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10035) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_size_t(msg, out_length); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Request( const AsymmetricKeyType* key_type, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10036; /* from _tee10036 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1175,7 +1285,7 @@ void OPK_Unpack_GenerateRandomCertificateKeyPair_Response( uint8_t** public_key, size_t** public_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10036) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, wrapped_private_key_length); OPK_UnpackNullable_size_t(msg, public_key_length); @@ -1206,10 +1316,123 @@ void OPK_Unpack_GenerateRandomCertificateKeyPair_Response( } } -ODK_Message OPK_Pack_DeviceKeyCoseSign1_Request( - const uint8_t* message, size_t message_length, const uint8_t* signature, - const size_t* signature_length) { - uint32_t api_value = 10034; /* from _tee10034 */ +ODK_Message OPK_Pack_GetSignedCsrPayload_Request( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length) { + uint32_t api_value = 10037; /* from _tee10037 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &challenge_length); + OPK_Pack_size_t(&msg, &encoded_device_info_length); + OPK_PackNullable_size_t(&msg, signed_csr_payload_length); + OPK_PackMemory(&msg, (const uint8_t*)challenge, + OPK_ToLengthType(challenge_length)); + OPK_PackMemory(&msg, (const uint8_t*)encoded_device_info, + OPK_ToLengthType(encoded_device_info_length)); + OPK_PackAlloc(&msg, signed_csr_payload); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetSignedCsrPayload_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** signed_csr_payload, + size_t** signed_csr_payload_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10037) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, signed_csr_payload_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(signed_csr_payload_length)); + if (p && *signed_csr_payload) { + memcpy(*signed_csr_payload, p, + OPK_SafeDerefSizeTPtrPtr(signed_csr_payload_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_MaxDeviceInfoSize_Request(void) { + uint32_t api_value = 10038; /* from _tee10038 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxDeviceInfoSize_Response(ODK_Message* msg, size_t* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10038) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetDeviceInformation_Request(const uint8_t* out, + const size_t* out_length) { + uint32_t api_value = 10039; /* from _tee10039 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackNullable_size_t(&msg, out_length); + OPK_PackAlloc(&msg, out); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceInformation_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** out, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10039) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, out_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(out_length)); + if (p && *out) { + memcpy(*out, p, OPK_SafeDerefSizeTPtrPtr(out_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_BccKeyCoseSign1_Request(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 10040; /* from _tee10040 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1224,13 +1447,13 @@ ODK_Message OPK_Pack_DeviceKeyCoseSign1_Request( return msg; } -void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, - OEMCryptoResult* result, - uint8_t** signature, - size_t** signature_length) { +void OPK_Unpack_BccKeyCoseSign1_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10034) + if (api_value != 10040) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -1251,8 +1474,71 @@ void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetMaxBccKeyCoseSign1Size_Request( + const size_t* out_length) { + uint32_t api_value = 10041; /* from _tee10041 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetMaxBccKeyCoseSign1Size_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 != 10041) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_size_t(msg, out_length); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetDeviceFusedStatus_Request(const bool* is_fused) { + uint32_t api_value = 10042; /* from _tee10042 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, is_fused); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceFusedStatus_Response(ODK_Message* msg, + OEMCryptoResult* result, + bool** is_fused) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10042) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_bool(msg, is_fused); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash) { - uint32_t api_value = 10035; /* from _tee10035 */ + uint32_t api_value = 10043; /* from _tee10043 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1267,7 +1553,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10035) + if (api_value != 10043) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1284,7 +1570,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, ODK_Message OPK_Pack_Crc32Cont_Request(const uint8_t* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10036; /* from _tee10036 */ + uint32_t api_value = 10044; /* from _tee10044 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1302,7 +1588,7 @@ void OPK_Unpack_Crc32Cont_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10036) + if (api_value != 10044) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1321,7 +1607,7 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10037; /* from _tee10037 */ + uint32_t api_value = 10045; /* from _tee10045 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1335,8 +1621,9 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in, const bool is_null = objs == NULL || OPK_LengthIsNull(count); if (!OPK_PackBoolValue(odk_message, is_null)) { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Pack_OPK_OutputBuffer(odk_message, - (const OPK_OutputBuffer*)(objs + i * size)); + const uint8_t* new_address = (const uint8_t*)objs + i * size; + OPK_Pack_OPK_OutputBuffer( + odk_message, (const OPK_OutputBuffer*)(const void*)new_address); } } OPK_Pack_size_t(&msg, &in_offset); @@ -1352,7 +1639,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10037) + if (api_value != 10045) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1367,7 +1654,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetTrustedTime_Request(const uint64_t* time_in_s) { - uint32_t api_value = 10038; /* from _tee10038 */ + uint32_t api_value = 10046; /* from _tee10046 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1383,7 +1670,7 @@ void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, uint64_t** time_in_s) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10038) + if (api_value != 10046) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1398,7 +1685,7 @@ void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, } ODK_Message OPK_Pack_InitializeClock_Request(void) { - uint32_t api_value = 10039; /* from _tee10039 */ + uint32_t api_value = 10047; /* from _tee10047 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1412,7 +1699,7 @@ void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10039) + if (api_value != 10047) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1426,7 +1713,7 @@ void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, } ODK_Message OPK_Pack_TerminateClock_Request(void) { - uint32_t api_value = 10040; /* from _tee10040 */ + uint32_t api_value = 10048; /* from _tee10048 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1440,7 +1727,7 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10040) + if (api_value != 10048) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1454,7 +1741,7 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetClockType_Request(void) { - uint32_t api_value = 10041; /* from _tee10041 */ + uint32_t api_value = 10049; /* from _tee10049 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1468,16 +1755,554 @@ void OPK_Unpack_GetClockType_Response(ODK_Message* msg, OEMCrypto_Clock_Security_Level* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10041) + if (api_value != 10049) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_Clock_Security_Level(msg, result); OPK_UnpackEOM(msg); OPK_SharedBuffer_FinalizeUnpacking(); } +ODK_Message OPK_Pack_GetSecurityLevel_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10050) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_OEMCrypto_Security_Level(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetProvisioningMethod_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10051) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_OEMCrypto_ProvisioningMethod(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetResourceRatingTier_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10052) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10053) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OPK_FeatureStatus(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsProductionReady_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10054) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetWatermarkingSupport_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_GetWatermarkingSupport_Response( + ODK_Message* msg, OEMCrypto_WatermarkingSupport* 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_OEMCrypto_WatermarkingSupport(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetCurrentSRMVersion_Request(const uint32_t* srm_version) { + uint32_t api_value = 10056; /* from _tee10056 */ + 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, srm_version); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetCurrentSRMVersion_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint32_t** srm_version) { + 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_UnpackNullable_uint32_t(msg, srm_version); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_IsAntiRollbackHWPresent_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_IsAntiRollbackHWPresent_Response(ODK_Message* msg, + bool* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10057) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ApplyCGMS_Request(uint8_t cgms_field) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint8_t(&msg, &cgms_field); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ApplyCGMS_Response(ODK_Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10058) + 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_IsCGMS_AActive_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10059) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_SupportsCGMS_A_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10060) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_HasAnalogDisplay_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10061) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsAnalogDisplayActive_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10062) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_CanDisableAnalogDisplay_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10063) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_DisableAnalogDisplay_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10064) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxBufferSizeForDecrypt_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxBufferSizeForDecrypt_Response(ODK_Message* msg, + size_t* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10065) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10066) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsClosedPlatform_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsClosedPlatform_Response(ODK_Message* msg, bool* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10067) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_CurrentHDCPCapability_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_CurrentHDCPCapability_Response( + ODK_Message* msg, OEMCrypto_HDCP_Capability* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10068) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_OEMCrypto_HDCP_Capability(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxHDCPCapability_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxHDCPCapability_Response(ODK_Message* msg, + OEMCrypto_HDCP_Capability* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10069) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_OEMCrypto_HDCP_Capability(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10070) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxSampleSize_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10071) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_SupportedCertificates_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10072) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ContentDecryptBypassesTA_Request(void) { + 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); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10073) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_bool(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + ODK_Message OPK_Pack_GetEncryptAndSignSize_Request( uint32_t context, size_t in_length, const size_t* wrapped_length) { - uint32_t api_value = 10042; /* from _tee10042 */ + uint32_t api_value = 10074; /* from _tee10074 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1495,7 +2320,7 @@ void OPK_Unpack_GetEncryptAndSignSize_Response(ODK_Message* msg, size_t** wrapped_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10042) + if (api_value != 10074) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1514,7 +2339,7 @@ ODK_Message OPK_Pack_EncryptAndSign_Request(uint32_t context, size_t data_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10043; /* from _tee10043 */ + uint32_t api_value = 10075; /* from _tee10075 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1534,7 +2359,7 @@ void OPK_Unpack_EncryptAndSign_Response(ODK_Message* msg, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10043) + if (api_value != 10075) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -1560,7 +2385,7 @@ ODK_Message OPK_Pack_VerifyAndDecrypt_Request(uint32_t context, size_t wrapped_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10044; /* from _tee10044 */ + uint32_t api_value = 10076; /* from _tee10076 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1581,7 +2406,7 @@ void OPK_Unpack_VerifyAndDecrypt_Response(ODK_Message* msg, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10044) + if (api_value != 10076) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -1605,7 +2430,7 @@ void OPK_Unpack_VerifyAndDecrypt_Response(ODK_Message* msg, ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Request( const uint8_t* wrapped, size_t wrapped_length, const uint8_t* signature, const uint8_t* iv, const uint8_t* out) { - uint32_t api_value = 10045; /* from _tee10045 */ + uint32_t api_value = 10077; /* from _tee10077 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1614,7 +2439,7 @@ ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Request( OPK_PackMemory(&msg, (const uint8_t*)wrapped, OPK_ToLengthType(wrapped_length)); OPK_PackNullable_uint8_t(&msg, signature); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_PackIsNull(&msg, out); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); @@ -1625,7 +2450,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Response( ODK_Message* msg, OEMCryptoResult* result, uint8_t** out) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10045) + if (api_value != 10077) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h index b28fc05..d72732b 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 @@ -12,6 +12,7 @@ #include "log_macros.h" #include "opk_serialization_base.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -123,6 +124,12 @@ ODK_Message OPK_Pack_K1_FreeKeyHandle_Request( WTPI_K1_SymmetricKey_Handle key_handle); void OPK_Unpack_K1_FreeKeyHandle_Response(ODK_Message* msg, OEMCryptoResult* result); +ODK_Message OPK_Pack_K1_PrepareExternalKeyHandle_Request( + WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* out_buffer, + const size_t* out_buffer_length); +void OPK_Unpack_K1_PrepareExternalKeyHandle_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** out_buffer, + size_t** out_buffer_length); ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Request( const uint8_t* input, size_t input_length, AsymmetricKeyType key_type, const WTPI_AsymmetricKey_Handle* key_handle); @@ -191,12 +198,23 @@ ODK_Message OPK_Pack_GetSignatureSize_Request(WTPI_AsymmetricKey_Handle key, void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length); +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Request( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + const OEMCrypto_SignatureHashAlgorithm* hash_algorithm); +void OPK_Unpack_GetSignatureHashAlgorithm_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SignatureHashAlgorithm** hash_algorithm); ODK_Message OPK_Pack_GetBootCertificateChain_Request(const uint8_t* out, const size_t* out_length); void OPK_Unpack_GetBootCertificateChain_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** out, size_t** out_length); +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Request( + const size_t* out_length); +void OPK_Unpack_GetMaxBootCertificateChainSize_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length); ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Request( const AsymmetricKeyType* key_type, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, @@ -205,14 +223,38 @@ void OPK_Unpack_GenerateRandomCertificateKeyPair_Response( ODK_Message* msg, OEMCryptoResult* result, AsymmetricKeyType** key_type, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, uint8_t** public_key, size_t** public_key_length); -ODK_Message OPK_Pack_DeviceKeyCoseSign1_Request(const uint8_t* message, - size_t message_length, - const uint8_t* signature, - const size_t* signature_length); -void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, - OEMCryptoResult* result, - uint8_t** signature, - size_t** signature_length); +ODK_Message OPK_Pack_GetSignedCsrPayload_Request( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + const uint8_t* signed_csr_payload, const size_t* signed_csr_payload_length); +void OPK_Unpack_GetSignedCsrPayload_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** signed_csr_payload, + size_t** signed_csr_payload_length); +ODK_Message OPK_Pack_MaxDeviceInfoSize_Request(void); +void OPK_Unpack_MaxDeviceInfoSize_Response(ODK_Message* msg, size_t* result); +ODK_Message OPK_Pack_GetDeviceInformation_Request(const uint8_t* out, + const size_t* out_length); +void OPK_Unpack_GetDeviceInformation_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** out, + size_t** out_length); +ODK_Message OPK_Pack_BccKeyCoseSign1_Request(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + const size_t* signature_length); +void OPK_Unpack_BccKeyCoseSign1_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** signature, + size_t** signature_length); +ODK_Message OPK_Pack_GetMaxBccKeyCoseSign1Size_Request( + const size_t* out_length); +void OPK_Unpack_GetMaxBccKeyCoseSign1Size_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length); +ODK_Message OPK_Pack_GetDeviceFusedStatus_Request(const bool* is_fused); +void OPK_Unpack_GetDeviceFusedStatus_Response(ODK_Message* msg, + OEMCryptoResult* result, + bool** is_fused); ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash); void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** initial_hash); @@ -242,6 +284,70 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetClockType_Request(void); void OPK_Unpack_GetClockType_Response(ODK_Message* msg, OEMCrypto_Clock_Security_Level* result); +ODK_Message OPK_Pack_GetSecurityLevel_Request(void); +void OPK_Unpack_GetSecurityLevel_Response(ODK_Message* msg, + OEMCrypto_Security_Level* result); +ODK_Message OPK_Pack_GetProvisioningMethod_Request(void); +void OPK_Unpack_GetProvisioningMethod_Response( + ODK_Message* msg, OEMCrypto_ProvisioningMethod* result); +ODK_Message OPK_Pack_GetResourceRatingTier_Request(void); +void OPK_Unpack_GetResourceRatingTier_Response(ODK_Message* msg, + uint32_t* result); +ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Request(void); +void OPK_Unpack_IsTAAntiRollbackEnabled_Response(ODK_Message* msg, + OPK_FeatureStatus* result); +ODK_Message OPK_Pack_IsProductionReady_Request(void); +void OPK_Unpack_IsProductionReady_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_GetWatermarkingSupport_Request(void); +void OPK_Unpack_GetWatermarkingSupport_Response( + ODK_Message* msg, OEMCrypto_WatermarkingSupport* result); +ODK_Message OPK_Pack_GetCurrentSRMVersion_Request(const uint32_t* srm_version); +void OPK_Unpack_GetCurrentSRMVersion_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint32_t** srm_version); +ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Request(void); +void OPK_Unpack_IsAntiRollbackHWPresent_Response(ODK_Message* msg, + bool* result); +ODK_Message OPK_Pack_ApplyCGMS_Request(uint8_t cgms_field); +void OPK_Unpack_ApplyCGMS_Response(ODK_Message* msg, OEMCryptoResult* result); +ODK_Message OPK_Pack_IsCGMS_AActive_Request(void); +void OPK_Unpack_IsCGMS_AActive_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_SupportsCGMS_A_Request(void); +void OPK_Unpack_SupportsCGMS_A_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_HasAnalogDisplay_Request(void); +void OPK_Unpack_HasAnalogDisplay_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_IsAnalogDisplayActive_Request(void); +void OPK_Unpack_IsAnalogDisplayActive_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_CanDisableAnalogDisplay_Request(void); +void OPK_Unpack_CanDisableAnalogDisplay_Response(ODK_Message* msg, + bool* result); +ODK_Message OPK_Pack_DisableAnalogDisplay_Request(void); +void OPK_Unpack_DisableAnalogDisplay_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_MaxBufferSizeForDecrypt_Request(void); +void OPK_Unpack_MaxBufferSizeForDecrypt_Response(ODK_Message* msg, + size_t* result); +ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Request(void); +void OPK_Unpack_MaxOutputSizeForDecrypt_Response(ODK_Message* msg, + size_t* result); +ODK_Message OPK_Pack_IsClosedPlatform_Request(void); +void OPK_Unpack_IsClosedPlatform_Response(ODK_Message* msg, bool* result); +ODK_Message OPK_Pack_CurrentHDCPCapability_Request(void); +void OPK_Unpack_CurrentHDCPCapability_Response( + ODK_Message* msg, OEMCrypto_HDCP_Capability* result); +ODK_Message OPK_Pack_MaxHDCPCapability_Request(void); +void OPK_Unpack_MaxHDCPCapability_Response(ODK_Message* msg, + OEMCrypto_HDCP_Capability* result); +ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Request(void); +void OPK_Unpack_MaxBufferSizeForGenericCrypto_Response(ODK_Message* msg, + size_t* result); +ODK_Message OPK_Pack_MaxSampleSize_Request(void); +void OPK_Unpack_MaxSampleSize_Response(ODK_Message* msg, size_t* result); +ODK_Message OPK_Pack_SupportedCertificates_Request(void); +void OPK_Unpack_SupportedCertificates_Response(ODK_Message* msg, + uint32_t* result); +ODK_Message OPK_Pack_ContentDecryptBypassesTA_Request(void); +void OPK_Unpack_ContentDecryptBypassesTA_Response(ODK_Message* msg, + bool* result); ODK_Message OPK_Pack_GetEncryptAndSignSize_Request( uint32_t context, size_t in_length, const size_t* wrapped_length); void OPK_Unpack_GetEncryptAndSignSize_Response(ODK_Message* msg, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp index 5df1c6d..8ad229c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp @@ -10,7 +10,7 @@ '../settings.gypi', ], 'variables': { - 'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/ipc-test/serialization_adapter', + 'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/common', }, 'targets' : [ { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/settings.gypi b/oemcrypto/opk/oemcrypto_ta/wtpi_test/settings.gypi index 70606e6..85c7fd7 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/settings.gypi +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/settings.gypi @@ -38,6 +38,12 @@ 'ENABLE_LOGGING=1', 'MIN_LOG_LEVEL=LOG_LEVEL_DEBUG', 'ENABLE_ANSI_COLORS=1', + 'OPK_CONFIG_SOC_VENDOR_NAME=test', + 'OPK_CONFIG_SOC_MODEL_NAME=test', + 'OPK_CONFIG_TEE_OS_NAME=TEE_Simulator', + 'OPK_CONFIG_TEE_OS_VERSION=0.0.0', + 'OPK_CONFIG_DEVICE_FORM_FACTOR=wtpi_test', + 'OPK_CONFIG_IMPLEMENTER_NAME=Widevine', ], } } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp index 9ffb463..81028a1 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp @@ -58,18 +58,17 @@ cleanup: bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length) { + size_t signature_length, const EVP_MD* digest) { boringssl_ptr md_ctx(EVP_MD_CTX_new()); EVP_PKEY_CTX* pkey_ctx = nullptr; - if (EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), + if (EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, digest, nullptr /* no ENGINE */, pkey) != 1) { LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature"); goto err; } - if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, - const_cast(EVP_sha1())) != 1) { + if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, digest) != 1) { LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature"); goto err; } @@ -79,6 +78,11 @@ bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, goto err; } + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()) != 1) { + LOGE("EVP_PKEY_CTX_set_rsa_mgf1_md failed in VerifyPSSSignature"); + goto err; + } + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, SHA_DIGEST_LENGTH) != 1) { LOGE("EVP_PKEY_CTX_set_rsa_pss_saltlen failed in VerifyPSSSignature"); goto err; @@ -104,6 +108,25 @@ err: return false; } +bool OecHashAlgorithmToOpenSslMd( + OEMCrypto_SignatureHashAlgorithm hash_algorithm, const EVP_MD** digest) { + switch (hash_algorithm) { + case OEMCrypto_SHA1: + *digest = EVP_sha1(); + return true; + case OEMCrypto_SHA2_256: + *digest = EVP_sha256(); + return true; + case OEMCrypto_SHA2_384: + *digest = EVP_sha384(); + return true; + case OEMCrypto_SHA2_512: + *digest = EVP_sha512(); + return true; + } + return false; +} + namespace wtpi_test { bool NewEccPrivateKey(EcKeyPtr* ec_key) { if (ec_key == nullptr) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h index d48c647..dfacc9e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h @@ -1,10 +1,13 @@ // Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. + #ifndef WTPI_TEST_SSL_UTIL_H_ #define WTPI_TEST_SSL_UTIL_H_ + #include +#include "OEMCryptoCENC.h" #include "openssl/aes.h" #include "openssl/bio.h" #include "openssl/ec.h" @@ -59,7 +62,10 @@ bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size, RSA** rsa); bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length); + size_t signature_length, const EVP_MD* digest); + +bool OecHashAlgorithmToOpenSslMd( + OEMCrypto_SignatureHashAlgorithm hash_algorithm, const EVP_MD** digest); namespace wtpi_test { // ECC Utils diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c index 8102d89..31c5391 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c @@ -26,6 +26,7 @@ #include "wtpi_clock_interface_layer1.h" #include "wtpi_device_key_interface.h" #include "wtpi_generation_number_interface.h" +#include "wtpi_provisioning_4_interface.h" static ODK_Message CreateEmptyMessage(void) { static uint8_t buffer[1]; @@ -162,12 +163,12 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Init_size_t((size_t*)&key_length); uint8_t* in_buffer; OPK_InitPointer((uint8_t**)&in_buffer); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); uint8_t* out_buffer; OPK_InitPointer((uint8_t**)&out_buffer); OPK_Unpack_C1_AESCBCDecrypt_Request(request, &key_handle, &key_length, - &in_buffer, &in_buffer_length, &iv[0], + &in_buffer, &in_buffer_length, &iv, &out_buffer); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; @@ -188,13 +189,12 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, (WTPI_K1_SymmetricKey_Handle*)&key_handle); uint8_t* in_buffer; OPK_InitPointer((uint8_t**)&in_buffer); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); uint8_t* out_buffer; OPK_InitPointer((uint8_t**)&out_buffer); OPK_Unpack_C1_AESCBCEncrypt_Request(request, &key_handle, &in_buffer, - &in_buffer_length, &iv[0], - &out_buffer); + &in_buffer_length, &iv, &out_buffer); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); @@ -397,14 +397,14 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, (WTPI_K1_SymmetricKey_Handle*)&decrypt_key_handle); uint8_t* enc_key; OPK_InitPointer((uint8_t**)&enc_key); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); SymmetricKeyType key_type; OPK_Init_SymmetricKeyType((SymmetricKeyType*)&key_type); WTPI_K1_SymmetricKey_Handle* out_key_handle; OPK_InitPointer((uint8_t**)&out_key_handle); OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request( - request, &decrypt_key_handle, &enc_key, &enc_key_length, &iv[0], + request, &decrypt_key_handle, &enc_key, &enc_key_length, &iv, &key_type, &out_key_handle); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; @@ -426,15 +426,15 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, (WTPI_K1_SymmetricKey_Handle*)&decrypt_key_handle); uint8_t* enc_mac_keys; OPK_InitPointer((uint8_t**)&enc_mac_keys); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); WTPI_K1_SymmetricKey_Handle* out_mac_key_server; OPK_InitPointer((uint8_t**)&out_mac_key_server); WTPI_K1_SymmetricKey_Handle* out_mac_key_client; OPK_InitPointer((uint8_t**)&out_mac_key_client); OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( request, &decrypt_key_handle, &enc_mac_keys, &enc_mac_keys_length, - &iv[0], &out_mac_key_server, &out_mac_key_client); + &iv, &out_mac_key_server, &out_mac_key_client); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); @@ -541,7 +541,28 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_K1_FreeKeyHandle_Response(result); break; } - case 10022: /* WTPI_CreateAsymmetricKeyHandle */ + case 10022: /* WTPI_K1_PrepareExternalKeyHandle */ + { + size_t* out_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(out_buffer_length); + WTPI_K1_SymmetricKey_Handle key_handle; + OPK_Init_WTPI_K1_SymmetricKey_Handle( + (WTPI_K1_SymmetricKey_Handle*)&key_handle); + uint8_t* out_buffer; + OPK_InitPointer((uint8_t**)&out_buffer); + OPK_Unpack_K1_PrepareExternalKeyHandle_Request( + request, &key_handle, &out_buffer, &out_buffer_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("K1_PrepareExternalKeyHandle"); + result = WTPI_K1_PrepareExternalKeyHandle(key_handle, out_buffer, + out_buffer_length); + *response = OPK_Pack_K1_PrepareExternalKeyHandle_Response( + result, out_buffer, out_buffer_length); + break; + } + case 10023: /* WTPI_CreateAsymmetricKeyHandle */ { size_t input_length; OPK_Init_size_t((size_t*)&input_length); @@ -563,7 +584,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_CreateAsymmetricKeyHandle_Response(result, key_handle); break; } - case 10023: /* WTPI_UnwrapIntoAsymmetricKeyHandle */ + case 10024: /* WTPI_UnwrapIntoAsymmetricKeyHandle */ { size_t input_length; OPK_Init_size_t((size_t*)&input_length); @@ -588,7 +609,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, result, key_handle, allowed_schemes); break; } - case 10024: /* WTPI_FreeAsymmetricKeyHandle */ + case 10025: /* WTPI_FreeAsymmetricKeyHandle */ { WTPI_AsymmetricKey_Handle key_handle; OPK_Init_WTPI_AsymmetricKey_Handle( @@ -602,7 +623,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_FreeAsymmetricKeyHandle_Response(result); break; } - case 10025: /* WTPI_GetWrappedAsymmetricKeySize */ + case 10026: /* WTPI_GetWrappedAsymmetricKeySize */ { size_t enc_private_key_length; OPK_Init_size_t((size_t*)&enc_private_key_length); @@ -622,7 +643,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetWrappedAsymmetricKeySize_Response(result, buffer_size); break; } - case 10026: /* WTPI_WrapAsymmetricKey */ + case 10027: /* WTPI_WrapAsymmetricKey */ { size_t output_length; OPK_Init_size_t((size_t*)&output_length); @@ -647,7 +668,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_WrapAsymmetricKey_Response(result, output, output_length); break; } - case 10027: /* WTPI_RSASign */ + case 10028: /* WTPI_RSASign */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -674,7 +695,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_RSASign_Response(result, signature, signature_length); break; } - case 10028: /* WTPI_RSADecrypt */ + case 10029: /* WTPI_RSADecrypt */ { size_t input_length; OPK_Init_size_t((size_t*)&input_length); @@ -696,7 +717,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_RSADecrypt_Response(result, out, out_length); break; } - case 10029: /* WTPI_ECCSign */ + case 10030: /* WTPI_ECCSign */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -720,7 +741,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_ECCSign_Response(result, signature, signature_length); break; } - case 10030: /* WTPI_ECCDeriveSessionKey */ + case 10031: /* WTPI_ECCDeriveSessionKey */ { size_t key_source_length; OPK_Init_size_t((size_t*)&key_source_length); @@ -745,7 +766,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, session_key_length); break; } - case 10031: /* WTPI_GetSignatureSize */ + case 10032: /* WTPI_GetSignatureSize */ { WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -760,7 +781,26 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetSignatureSize_Response(result, signature_length); break; } - case 10032: /* WTPI_GetBootCertificateChain */ + case 10033: /* WTPI_GetSignatureHashAlgorithm */ + { + WTPI_AsymmetricKey_Handle key; + OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); + AsymmetricKeyType key_type; + OPK_Init_AsymmetricKeyType((AsymmetricKeyType*)&key_type); + OEMCrypto_SignatureHashAlgorithm* hash_algorithm; + OPK_InitPointer((uint8_t**)&hash_algorithm); + OPK_Unpack_GetSignatureHashAlgorithm_Request(request, &key, &key_type, + &hash_algorithm); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetSignatureHashAlgorithm"); + result = WTPI_GetSignatureHashAlgorithm(key, key_type, hash_algorithm); + *response = + OPK_Pack_GetSignatureHashAlgorithm_Response(result, hash_algorithm); + break; + } + case 10034: /* WTPI_GetBootCertificateChain */ { size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); OPK_Init_size_t(out_length); @@ -776,7 +816,21 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetBootCertificateChain_Response(result, out, out_length); break; } - case 10033: /* WTPI_GenerateRandomCertificateKeyPair */ + case 10035: /* WTPI_GetMaxBootCertificateChainSize */ + { + size_t* out_length; + OPK_InitPointer((uint8_t**)&out_length); + OPK_Unpack_GetMaxBootCertificateChainSize_Request(request, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetMaxBootCertificateChainSize"); + result = WTPI_GetMaxBootCertificateChainSize(out_length); + *response = + OPK_Pack_GetMaxBootCertificateChainSize_Response(result, out_length); + break; + } + case 10036: /* WTPI_GenerateRandomCertificateKeyPair */ { size_t* wrapped_private_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); @@ -804,7 +858,64 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, public_key, public_key_length); break; } - case 10034: /* WTPI_DeviceKeyCoseSign1 */ + case 10037: /* WTPI_GetSignedCsrPayload */ + { + size_t challenge_length; + OPK_Init_size_t((size_t*)&challenge_length); + 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)); + OPK_Init_size_t(signed_csr_payload_length); + uint8_t* challenge; + OPK_InitPointer((uint8_t**)&challenge); + uint8_t* encoded_device_info; + OPK_InitPointer((uint8_t**)&encoded_device_info); + uint8_t* signed_csr_payload; + OPK_InitPointer((uint8_t**)&signed_csr_payload); + OPK_Unpack_GetSignedCsrPayload_Request( + request, &challenge, &challenge_length, &encoded_device_info, + &encoded_device_info_length, &signed_csr_payload, + &signed_csr_payload_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetSignedCsrPayload"); + result = WTPI_GetSignedCsrPayload( + challenge, challenge_length, encoded_device_info, + encoded_device_info_length, signed_csr_payload, + signed_csr_payload_length); + *response = OPK_Pack_GetSignedCsrPayload_Response( + result, signed_csr_payload, signed_csr_payload_length); + break; + } + case 10038: /* WTPI_MaxDeviceInfoSize */ + { + OPK_Unpack_MaxDeviceInfoSize_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + size_t result; + OPK_Init_size_t((size_t*)&result); + LOGD("MaxDeviceInfoSize"); + result = WTPI_MaxDeviceInfoSize(); + *response = OPK_Pack_MaxDeviceInfoSize_Response(result); + break; + } + case 10039: /* WTPI_GetDeviceInformation */ + { + size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(out_length); + uint8_t* out; + OPK_InitPointer((uint8_t**)&out); + OPK_Unpack_GetDeviceInformation_Request(request, &out, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetDeviceInformation"); + result = WTPI_GetDeviceInformation(out, out_length); + *response = + OPK_Pack_GetDeviceInformation_Response(result, out, out_length); + break; + } + case 10040: /* WTPI_BccKeyCoseSign1 */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -814,19 +925,46 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_InitPointer((uint8_t**)&message); uint8_t* signature; OPK_InitPointer((uint8_t**)&signature); - OPK_Unpack_DeviceKeyCoseSign1_Request(request, &message, &message_length, - &signature, &signature_length); + OPK_Unpack_BccKeyCoseSign1_Request(request, &message, &message_length, + &signature, &signature_length); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); - LOGD("DeviceKeyCoseSign1"); - result = WTPI_DeviceKeyCoseSign1(message, message_length, signature, - signature_length); - *response = OPK_Pack_DeviceKeyCoseSign1_Response(result, signature, - signature_length); + LOGD("BccKeyCoseSign1"); + result = WTPI_BccKeyCoseSign1(message, message_length, signature, + signature_length); + *response = OPK_Pack_BccKeyCoseSign1_Response(result, signature, + signature_length); break; } - case 10035: /* WTPI_Crc32Init */ + case 10041: /* WTPI_GetMaxBccKeyCoseSign1Size */ + { + size_t* out_length; + OPK_InitPointer((uint8_t**)&out_length); + OPK_Unpack_GetMaxBccKeyCoseSign1Size_Request(request, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetMaxBccKeyCoseSign1Size"); + result = WTPI_GetMaxBccKeyCoseSign1Size(out_length); + *response = + OPK_Pack_GetMaxBccKeyCoseSign1Size_Response(result, out_length); + break; + } + case 10042: /* WTPI_GetDeviceFusedStatus */ + { + bool* is_fused; + OPK_InitPointer((uint8_t**)&is_fused); + OPK_Unpack_GetDeviceFusedStatus_Request(request, &is_fused); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetDeviceFusedStatus"); + result = WTPI_GetDeviceFusedStatus(is_fused); + *response = OPK_Pack_GetDeviceFusedStatus_Response(result, is_fused); + break; + } + case 10043: /* WTPI_Crc32Init */ { uint32_t* initial_hash; OPK_InitPointer((uint8_t**)&initial_hash); @@ -839,7 +977,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Init_Response(result, initial_hash); break; } - case 10036: /* WTPI_Crc32Cont */ + case 10044: /* WTPI_Crc32Cont */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -859,7 +997,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_Response(result, new_crc); break; } - case 10037: /* WTPI_Crc32Cont_OutputBuffer */ + case 10045: /* WTPI_Crc32Cont_OutputBuffer */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -882,7 +1020,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_OutputBuffer_Response(result, new_crc); break; } - case 10038: /* WTPI_GetTrustedTime */ + case 10046: /* WTPI_GetTrustedTime */ { uint64_t* time_in_s; OPK_InitPointer((uint8_t**)&time_in_s); @@ -895,7 +1033,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetTrustedTime_Response(result, time_in_s); break; } - case 10039: /* WTPI_InitializeClock */ + case 10047: /* WTPI_InitializeClock */ { OPK_Unpack_InitializeClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -906,7 +1044,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_InitializeClock_Response(result); break; } - case 10040: /* WTPI_TerminateClock */ + case 10048: /* WTPI_TerminateClock */ { OPK_Unpack_TerminateClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -917,7 +1055,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_TerminateClock_Response(result); break; } - case 10041: /* WTPI_GetClockType */ + case 10049: /* WTPI_GetClockType */ { OPK_Unpack_GetClockType_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -929,7 +1067,277 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetClockType_Response(result); break; } - case 10042: /* WTPI_GetEncryptAndSignSize */ + case 10050: /* WTPI_GetSecurityLevel */ + { + OPK_Unpack_GetSecurityLevel_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_Security_Level result; + OPK_Init_OEMCrypto_Security_Level((OEMCrypto_Security_Level*)&result); + LOGD("GetSecurityLevel"); + result = WTPI_GetSecurityLevel(); + *response = OPK_Pack_GetSecurityLevel_Response(result); + break; + } + case 10051: /* WTPI_GetProvisioningMethod */ + { + OPK_Unpack_GetProvisioningMethod_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_ProvisioningMethod result; + OPK_Init_OEMCrypto_ProvisioningMethod( + (OEMCrypto_ProvisioningMethod*)&result); + LOGD("GetProvisioningMethod"); + result = WTPI_GetProvisioningMethod(); + *response = OPK_Pack_GetProvisioningMethod_Response(result); + break; + } + case 10052: /* WTPI_GetResourceRatingTier */ + { + OPK_Unpack_GetResourceRatingTier_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + uint32_t result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetResourceRatingTier"); + result = WTPI_GetResourceRatingTier(); + *response = OPK_Pack_GetResourceRatingTier_Response(result); + break; + } + case 10053: /* WTPI_IsTAAntiRollbackEnabled */ + { + OPK_Unpack_IsTAAntiRollbackEnabled_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OPK_FeatureStatus result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("IsTAAntiRollbackEnabled"); + result = WTPI_IsTAAntiRollbackEnabled(); + *response = OPK_Pack_IsTAAntiRollbackEnabled_Response(result); + break; + } + case 10054: /* WTPI_IsProductionReady */ + { + OPK_Unpack_IsProductionReady_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("IsProductionReady"); + result = WTPI_IsProductionReady(); + *response = OPK_Pack_IsProductionReady_Response(result); + break; + } + case 10055: /* WTPI_GetWatermarkingSupport */ + { + OPK_Unpack_GetWatermarkingSupport_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_WatermarkingSupport result; + OPK_Init_OEMCrypto_WatermarkingSupport( + (OEMCrypto_WatermarkingSupport*)&result); + LOGD("GetWatermarkingSupport"); + result = WTPI_GetWatermarkingSupport(); + *response = OPK_Pack_GetWatermarkingSupport_Response(result); + break; + } + case 10056: /* WTPI_GetCurrentSRMVersion */ + { + uint32_t* srm_version; + OPK_InitPointer((uint8_t**)&srm_version); + OPK_Unpack_GetCurrentSRMVersion_Request(request, &srm_version); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetCurrentSRMVersion"); + result = WTPI_GetCurrentSRMVersion(srm_version); + *response = OPK_Pack_GetCurrentSRMVersion_Response(result, srm_version); + break; + } + case 10057: /* WTPI_IsAntiRollbackHWPresent */ + { + OPK_Unpack_IsAntiRollbackHWPresent_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("IsAntiRollbackHWPresent"); + result = WTPI_IsAntiRollbackHWPresent(); + *response = OPK_Pack_IsAntiRollbackHWPresent_Response(result); + break; + } + case 10058: /* WTPI_ApplyCGMS */ + { + uint8_t cgms_field; + OPK_Init_uint8_t((uint8_t*)&cgms_field); + OPK_Unpack_ApplyCGMS_Request(request, &cgms_field); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("ApplyCGMS"); + result = WTPI_ApplyCGMS(cgms_field); + *response = OPK_Pack_ApplyCGMS_Response(result); + break; + } + case 10059: /* WTPI_IsCGMS_AActive */ + { + OPK_Unpack_IsCGMS_AActive_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("IsCGMS_AActive"); + result = WTPI_IsCGMS_AActive(); + *response = OPK_Pack_IsCGMS_AActive_Response(result); + break; + } + case 10060: /* WTPI_SupportsCGMS_A */ + { + OPK_Unpack_SupportsCGMS_A_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("SupportsCGMS_A"); + result = WTPI_SupportsCGMS_A(); + *response = OPK_Pack_SupportsCGMS_A_Response(result); + break; + } + case 10061: /* WTPI_HasAnalogDisplay */ + { + OPK_Unpack_HasAnalogDisplay_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("HasAnalogDisplay"); + result = WTPI_HasAnalogDisplay(); + *response = OPK_Pack_HasAnalogDisplay_Response(result); + break; + } + case 10062: /* WTPI_IsAnalogDisplayActive */ + { + OPK_Unpack_IsAnalogDisplayActive_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("IsAnalogDisplayActive"); + result = WTPI_IsAnalogDisplayActive(); + *response = OPK_Pack_IsAnalogDisplayActive_Response(result); + break; + } + case 10063: /* WTPI_CanDisableAnalogDisplay */ + { + OPK_Unpack_CanDisableAnalogDisplay_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("CanDisableAnalogDisplay"); + result = WTPI_CanDisableAnalogDisplay(); + *response = OPK_Pack_CanDisableAnalogDisplay_Response(result); + break; + } + case 10064: /* WTPI_DisableAnalogDisplay */ + { + OPK_Unpack_DisableAnalogDisplay_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("DisableAnalogDisplay"); + result = WTPI_DisableAnalogDisplay(); + *response = OPK_Pack_DisableAnalogDisplay_Response(result); + break; + } + case 10065: /* WTPI_MaxBufferSizeForDecrypt */ + { + OPK_Unpack_MaxBufferSizeForDecrypt_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + size_t result; + OPK_Init_size_t((size_t*)&result); + LOGD("MaxBufferSizeForDecrypt"); + result = WTPI_MaxBufferSizeForDecrypt(); + *response = OPK_Pack_MaxBufferSizeForDecrypt_Response(result); + break; + } + case 10066: /* WTPI_MaxOutputSizeForDecrypt */ + { + OPK_Unpack_MaxOutputSizeForDecrypt_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + size_t result; + OPK_Init_size_t((size_t*)&result); + LOGD("MaxOutputSizeForDecrypt"); + result = WTPI_MaxOutputSizeForDecrypt(); + *response = OPK_Pack_MaxOutputSizeForDecrypt_Response(result); + break; + } + case 10067: /* WTPI_IsClosedPlatform */ + { + OPK_Unpack_IsClosedPlatform_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("IsClosedPlatform"); + result = WTPI_IsClosedPlatform(); + *response = OPK_Pack_IsClosedPlatform_Response(result); + break; + } + case 10068: /* WTPI_CurrentHDCPCapability */ + { + OPK_Unpack_CurrentHDCPCapability_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_HDCP_Capability result; + OPK_Init_OEMCrypto_HDCP_Capability((OEMCrypto_HDCP_Capability*)&result); + LOGD("CurrentHDCPCapability"); + result = WTPI_CurrentHDCPCapability(); + *response = OPK_Pack_CurrentHDCPCapability_Response(result); + break; + } + case 10069: /* WTPI_MaxHDCPCapability */ + { + OPK_Unpack_MaxHDCPCapability_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_HDCP_Capability result; + OPK_Init_OEMCrypto_HDCP_Capability((OEMCrypto_HDCP_Capability*)&result); + LOGD("MaxHDCPCapability"); + result = WTPI_MaxHDCPCapability(); + *response = OPK_Pack_MaxHDCPCapability_Response(result); + break; + } + case 10070: /* WTPI_MaxBufferSizeForGenericCrypto */ + { + OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + size_t result; + OPK_Init_size_t((size_t*)&result); + LOGD("MaxBufferSizeForGenericCrypto"); + result = WTPI_MaxBufferSizeForGenericCrypto(); + *response = OPK_Pack_MaxBufferSizeForGenericCrypto_Response(result); + break; + } + case 10071: /* WTPI_MaxSampleSize */ + { + OPK_Unpack_MaxSampleSize_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + size_t result; + OPK_Init_size_t((size_t*)&result); + LOGD("MaxSampleSize"); + result = WTPI_MaxSampleSize(); + *response = OPK_Pack_MaxSampleSize_Response(result); + break; + } + case 10072: /* WTPI_SupportedCertificates */ + { + OPK_Unpack_SupportedCertificates_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + uint32_t result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("SupportedCertificates"); + result = WTPI_SupportedCertificates(); + *response = OPK_Pack_SupportedCertificates_Response(result); + break; + } + case 10073: /* WTPI_ContentDecryptBypassesTA */ + { + OPK_Unpack_ContentDecryptBypassesTA_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + bool result; + OPK_Init_bool((bool*)&result); + LOGD("ContentDecryptBypassesTA"); + result = WTPI_ContentDecryptBypassesTA(); + *response = OPK_Pack_ContentDecryptBypassesTA_Response(result); + break; + } + case 10074: /* WTPI_GetEncryptAndSignSize */ { uint32_t context; OPK_Init_uint32_t((uint32_t*)&context); @@ -948,7 +1356,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetEncryptAndSignSize_Response(result, wrapped_length); break; } - case 10043: /* WTPI_EncryptAndSign */ + case 10075: /* WTPI_EncryptAndSign */ { size_t data_length; OPK_Init_size_t((size_t*)&data_length); @@ -970,7 +1378,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_EncryptAndSign_Response(result, out, out_length); break; } - case 10044: /* WTPI_VerifyAndDecrypt */ + case 10076: /* WTPI_VerifyAndDecrypt */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); @@ -993,7 +1401,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_VerifyAndDecrypt_Response(result, out, out_length); break; } - case 10045: /* WTPI_VerifyAndDecryptUsageData_Legacy */ + case 10077: /* WTPI_VerifyAndDecryptUsageData_Legacy */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); @@ -1001,12 +1409,12 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_InitPointer((uint8_t**)&wrapped); uint8_t* signature = (uint8_t*)OPK_VarAlloc(sizeof(uint8_t)); OPK_Init_uint8_t((uint8_t*)signature); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); uint8_t* out; OPK_InitPointer((uint8_t**)&out); OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( - request, &wrapped, &wrapped_length, &signature, &iv[0], &out); + request, &wrapped, &wrapped_length, &signature, &iv, &out); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c index 5019d6a..84c9954 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 @@ -22,6 +22,7 @@ #include "shared_buffer_allocator.h" #include "tee_special_cases.h" #include "tos_transport_interface.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -125,7 +126,7 @@ ODK_Message OPK_Pack_K1_GetKeySize_Response(OEMCryptoResult result, void OPK_Unpack_C1_AESCBCDecrypt_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, size_t* key_length, uint8_t** in_buffer, size_t* in_buffer_length, - uint8_t* iv, uint8_t** out_buffer) { + uint8_t** iv, uint8_t** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); if (api_value != 10004) @@ -137,7 +138,7 @@ void OPK_Unpack_C1_AESCBCDecrypt_Request( OPK_Unpack_size_t(msg, key_length); OPK_UnpackInPlace(msg, (uint8_t**)in_buffer, OPK_FromSizeTPtr(in_buffer_length)); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); *out_buffer = (uint8_t*)OPK_UnpackAllocBuffer( msg, OPK_FromSizeTPtr(in_buffer_length), sizeof(uint8_t)); OPK_UnpackEOM(msg); @@ -163,7 +164,7 @@ ODK_Message OPK_Pack_C1_AESCBCDecrypt_Response(OEMCryptoResult result, void OPK_Unpack_C1_AESCBCEncrypt_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, - uint8_t** in_buffer, size_t* in_buffer_length, uint8_t* iv, + uint8_t** in_buffer, size_t* in_buffer_length, uint8_t** iv, uint8_t** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -175,7 +176,7 @@ void OPK_Unpack_C1_AESCBCEncrypt_Request( OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle); OPK_UnpackInPlace(msg, (uint8_t**)in_buffer, OPK_FromSizeTPtr(in_buffer_length)); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); *out_buffer = (uint8_t*)OPK_UnpackAllocBuffer( msg, OPK_FromSizeTPtr(in_buffer_length), sizeof(uint8_t)); OPK_UnpackEOM(msg); @@ -374,7 +375,7 @@ ODK_Message OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Response( void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle, - uint8_t** enc_key, size_t* enc_key_length, uint8_t* iv, + uint8_t** enc_key, size_t* enc_key_length, uint8_t** iv, SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -385,7 +386,7 @@ void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request( OPK_Unpack_size_t(msg, enc_key_length); OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, decrypt_key_handle); OPK_UnpackInPlace(msg, (uint8_t**)enc_key, OPK_FromSizeTPtr(enc_key_length)); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); OPK_Unpack_SymmetricKeyType(msg, key_type); *out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc( msg, sizeof(WTPI_K1_SymmetricKey_Handle)); @@ -407,7 +408,7 @@ ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Response( void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle, - uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t* iv, + uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t** iv, WTPI_K1_SymmetricKey_Handle** out_mac_key_server, WTPI_K1_SymmetricKey_Handle** out_mac_key_client) { uint32_t api_value = UINT32_MAX; @@ -420,7 +421,7 @@ void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, decrypt_key_handle); OPK_UnpackInPlace(msg, (uint8_t**)enc_mac_keys, OPK_FromSizeTPtr(enc_mac_keys_length)); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); *out_mac_key_server = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc( msg, sizeof(WTPI_K1_SymmetricKey_Handle)); *out_mac_key_client = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc( @@ -572,12 +573,46 @@ ODK_Message OPK_Pack_K1_FreeKeyHandle_Response(OEMCryptoResult result) { return msg; } +void OPK_Unpack_K1_PrepareExternalKeyHandle_Request( + ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, + uint8_t** out_buffer, size_t** out_buffer_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10022) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackNullable_size_t(msg, out_buffer_length); + OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle); + *out_buffer = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(out_buffer_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_K1_PrepareExternalKeyHandle_Response( + OEMCryptoResult result, const uint8_t* out_buffer, + const size_t* out_buffer_length) { + uint32_t api_value = 10022; /* from _tee10022 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, out_buffer_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)out_buffer, + OPK_FromSizeTPtr(out_buffer_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_CreateAsymmetricKeyHandle_Request( ODK_Message* msg, uint8_t** input, size_t* input_length, AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10022) + if (api_value != 10023) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -592,7 +627,7 @@ void OPK_Unpack_CreateAsymmetricKeyHandle_Request( ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Response( OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle) { - uint32_t api_value = 10022; /* from _tee10022 */ + uint32_t api_value = 10023; /* from _tee10023 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -608,7 +643,7 @@ void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Request( uint32_t** allowed_schemes) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10023) + if (api_value != 10024) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -625,7 +660,7 @@ void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Request( ODK_Message OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Response( OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle, const uint32_t* allowed_schemes) { - uint32_t api_value = 10023; /* from _tee10023 */ + uint32_t api_value = 10024; /* from _tee10024 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -640,7 +675,7 @@ void OPK_Unpack_FreeAsymmetricKeyHandle_Request( ODK_Message* msg, WTPI_AsymmetricKey_Handle* key_handle) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10024) + if (api_value != 10025) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -650,7 +685,7 @@ void OPK_Unpack_FreeAsymmetricKeyHandle_Request( } ODK_Message OPK_Pack_FreeAsymmetricKeyHandle_Response(OEMCryptoResult result) { - uint32_t api_value = 10024; /* from _tee10024 */ + uint32_t api_value = 10025; /* from _tee10025 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -664,7 +699,7 @@ void OPK_Unpack_GetWrappedAsymmetricKeySize_Request( AsymmetricKeyType* key_type, size_t** buffer_size) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10025) + if (api_value != 10026) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -677,7 +712,7 @@ void OPK_Unpack_GetWrappedAsymmetricKeySize_Request( ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Response( OEMCryptoResult result, const size_t* buffer_size) { - uint32_t api_value = 10025; /* from _tee10025 */ + uint32_t api_value = 10026; /* from _tee10026 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -694,7 +729,7 @@ void OPK_Unpack_WrapAsymmetricKey_Request(ODK_Message* msg, uint8_t** output, size_t* clear_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10026) + if (api_value != 10027) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -712,7 +747,7 @@ void OPK_Unpack_WrapAsymmetricKey_Request(ODK_Message* msg, uint8_t** output, ODK_Message OPK_Pack_WrapAsymmetricKey_Response(OEMCryptoResult result, const uint8_t* output, size_t output_length) { - uint32_t api_value = 10026; /* from _tee10026 */ + uint32_t api_value = 10027; /* from _tee10027 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &output_length); @@ -733,7 +768,7 @@ void OPK_Unpack_RSASign_Request(ODK_Message* msg, RSA_Padding_Scheme* padding_scheme) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10027) + if (api_value != 10028) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -751,7 +786,7 @@ void OPK_Unpack_RSASign_Request(ODK_Message* msg, ODK_Message OPK_Pack_RSASign_Response(OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10027; /* from _tee10027 */ + uint32_t api_value = 10028; /* from _tee10028 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -771,7 +806,7 @@ void OPK_Unpack_RSADecrypt_Request(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 != 10028) + if (api_value != 10029) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -788,7 +823,7 @@ void OPK_Unpack_RSADecrypt_Request(ODK_Message* msg, ODK_Message OPK_Pack_RSADecrypt_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10028; /* from _tee10028 */ + uint32_t api_value = 10029; /* from _tee10029 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -808,7 +843,7 @@ void OPK_Unpack_ECCSign_Request(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10029) + if (api_value != 10030) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -825,7 +860,7 @@ void OPK_Unpack_ECCSign_Request(ODK_Message* msg, ODK_Message OPK_Pack_ECCSign_Response(OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10029; /* from _tee10029 */ + uint32_t api_value = 10030; /* from _tee10030 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -847,7 +882,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg, size_t** session_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10030) + if (api_value != 10031) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -865,7 +900,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg, ODK_Message OPK_Pack_ECCDeriveSessionKey_Response( OEMCryptoResult result, const uint8_t* session_key, const size_t* session_key_length) { - uint32_t api_value = 10030; /* from _tee10030 */ + uint32_t api_value = 10031; /* from _tee10031 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, session_key_length); @@ -884,7 +919,7 @@ void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10031) + if (api_value != 10032) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -896,7 +931,7 @@ void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result, const size_t* signature_length) { - uint32_t api_value = 10031; /* from _tee10031 */ + uint32_t api_value = 10032; /* from _tee10032 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -906,11 +941,42 @@ ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result, return msg; } +void OPK_Unpack_GetSignatureHashAlgorithm_Request( + ODK_Message* msg, WTPI_AsymmetricKey_Handle* key, + AsymmetricKeyType* key_type, + OEMCrypto_SignatureHashAlgorithm** hash_algorithm) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10033) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key); + OPK_Unpack_AsymmetricKeyType(msg, key_type); + *hash_algorithm = (OEMCrypto_SignatureHashAlgorithm*)OPK_UnpackAlloc( + msg, sizeof(OEMCrypto_SignatureHashAlgorithm)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Response( + OEMCryptoResult result, + const OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + uint32_t api_value = 10033; /* from _tee10033 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_OEMCrypto_SignatureHashAlgorithm(&msg, hash_algorithm); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_GetBootCertificateChain_Request(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 != 10032) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -923,7 +989,7 @@ void OPK_Unpack_GetBootCertificateChain_Request(ODK_Message* msg, uint8_t** out, ODK_Message OPK_Pack_GetBootCertificateChain_Response( OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10032; /* from _tee10032 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -936,13 +1002,38 @@ ODK_Message OPK_Pack_GetBootCertificateChain_Response( return msg; } +void OPK_Unpack_GetMaxBootCertificateChainSize_Request(ODK_Message* msg, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10035) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *out_length = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Response( + OEMCryptoResult result, const size_t* out_length) { + uint32_t api_value = 10035; /* from _tee10035 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_size_t(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_GenerateRandomCertificateKeyPair_Request( ODK_Message* msg, AsymmetricKeyType** key_type, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, uint8_t** public_key, size_t** public_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10036) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -963,7 +1054,7 @@ ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Response( const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10036; /* from _tee10036 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, wrapped_private_key_length); @@ -983,13 +1074,105 @@ ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Response( return msg; } -void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, - size_t* message_length, - uint8_t** signature, - size_t** signature_length) { +void OPK_Unpack_GetSignedCsrPayload_Request( + ODK_Message* msg, uint8_t** challenge, size_t* challenge_length, + uint8_t** encoded_device_info, size_t* encoded_device_info_length, + uint8_t** signed_csr_payload, size_t** signed_csr_payload_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10034) + if (api_value != 10037) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, challenge_length); + OPK_Unpack_size_t(msg, encoded_device_info_length); + OPK_UnpackNullable_size_t(msg, signed_csr_payload_length); + OPK_UnpackInPlace(msg, (uint8_t**)challenge, + OPK_FromSizeTPtr(challenge_length)); + OPK_UnpackInPlace(msg, (uint8_t**)encoded_device_info, + OPK_FromSizeTPtr(encoded_device_info_length)); + *signed_csr_payload = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(signed_csr_payload_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetSignedCsrPayload_Response( + OEMCryptoResult result, const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length) { + uint32_t api_value = 10037; /* from _tee10037 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, signed_csr_payload_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)signed_csr_payload, + OPK_FromSizeTPtr(signed_csr_payload_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxDeviceInfoSize_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10038) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxDeviceInfoSize_Response(size_t result) { + uint32_t api_value = 10038; /* from _tee10038 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceInformation_Request(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 != 10039) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackNullable_size_t(msg, out_length); + *out = (uint8_t*)OPK_UnpackAllocBuffer(msg, OPK_FromSizeTPtrPtr(out_length), + sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetDeviceInformation_Response(OEMCryptoResult result, + const uint8_t* out, + const size_t* out_length) { + uint32_t api_value = 10039; /* from _tee10039 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, out_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)out, OPK_FromSizeTPtr(out_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_BccKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, + size_t* message_length, + uint8_t** signature, + size_t** signature_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10040) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1002,10 +1185,10 @@ void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, OPK_SharedBuffer_FinalizeUnpacking(); } -ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( - OEMCryptoResult result, const uint8_t* signature, - const size_t* signature_length) { - uint32_t api_value = 10034; /* from _tee10034 */ +ODK_Message OPK_Pack_BccKeyCoseSign1_Response(OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length) { + uint32_t api_value = 10040; /* from _tee10040 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -1019,10 +1202,60 @@ ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( return msg; } +void OPK_Unpack_GetMaxBccKeyCoseSign1Size_Request(ODK_Message* msg, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10041) + 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_GetMaxBccKeyCoseSign1Size_Response( + OEMCryptoResult result, const size_t* out_length) { + uint32_t api_value = 10041; /* from _tee10041 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_size_t(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceFusedStatus_Request(ODK_Message* msg, + bool** is_fused) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10042) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *is_fused = (bool*)OPK_UnpackAlloc(msg, sizeof(bool)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetDeviceFusedStatus_Response(OEMCryptoResult result, + const bool* is_fused) { + uint32_t api_value = 10042; /* from _tee10042 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_bool(&msg, is_fused); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10035) + if (api_value != 10043) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1033,7 +1266,7 @@ void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result, const uint32_t* initial_hash) { - uint32_t api_value = 10035; /* from _tee10035 */ + uint32_t api_value = 10043; /* from _tee10043 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1048,7 +1281,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10036) + if (api_value != 10044) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1062,7 +1295,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, ODK_Message OPK_Pack_Crc32Cont_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10036; /* from _tee10036 */ + uint32_t api_value = 10044; /* from _tee10044 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1077,7 +1310,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10037) + if (api_value != 10045) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1101,8 +1334,9 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); } else { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + uint8_t* new_address = (uint8_t*)(*address) + size * i; OPK_Unpack_OPK_OutputBuffer( - odk_message, (OPK_OutputBuffer*)((*address) + size * i)); + odk_message, (OPK_OutputBuffer*)((void*)new_address)); } } } @@ -1117,7 +1351,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10037; /* from _tee10037 */ + uint32_t api_value = 10045; /* from _tee10045 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1130,7 +1364,7 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10038) + if (api_value != 10046) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1141,7 +1375,7 @@ void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s) { ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, const uint64_t* time_in_s) { - uint32_t api_value = 10038; /* from _tee10038 */ + uint32_t api_value = 10046; /* from _tee10046 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1154,7 +1388,7 @@ ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10039) + if (api_value != 10047) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1163,7 +1397,7 @@ void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10039; /* from _tee10039 */ + uint32_t api_value = 10047; /* from _tee10047 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1175,7 +1409,7 @@ ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10040) + if (api_value != 10048) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1184,7 +1418,7 @@ void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10040; /* from _tee10040 */ + uint32_t api_value = 10048; /* from _tee10048 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1196,7 +1430,7 @@ ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10041) + if (api_value != 10049) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1206,7 +1440,7 @@ void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetClockType_Response( OEMCrypto_Clock_Security_Level result) { - uint32_t api_value = 10041; /* from _tee10041 */ + uint32_t api_value = 10049; /* from _tee10049 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_Clock_Security_Level(&msg, &result); @@ -1215,13 +1449,528 @@ ODK_Message OPK_Pack_GetClockType_Response( return msg; } +void OPK_Unpack_GetSecurityLevel_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10050) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetSecurityLevel_Response( + OEMCrypto_Security_Level result) { + uint32_t api_value = 10050; /* from _tee10050 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_Security_Level(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetProvisioningMethod_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10051) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetProvisioningMethod_Response( + OEMCrypto_ProvisioningMethod result) { + uint32_t api_value = 10051; /* from _tee10051 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_ProvisioningMethod(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetResourceRatingTier_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10052) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetResourceRatingTier_Response(uint32_t result) { + 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); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsTAAntiRollbackEnabled_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10053) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Response( + OPK_FeatureStatus result) { + 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); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsProductionReady_Request(ODK_Message* msg) { + 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); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsProductionReady_Response(bool result) { + uint32_t api_value = 10054; /* from _tee10054 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetWatermarkingSupport_Request(ODK_Message* msg) { + 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); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetWatermarkingSupport_Response( + OEMCrypto_WatermarkingSupport result) { + uint32_t api_value = 10055; /* from _tee10055 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_WatermarkingSupport(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetCurrentSRMVersion_Request(ODK_Message* msg, + uint32_t** srm_version) { + 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); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *srm_version = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetCurrentSRMVersion_Response( + OEMCryptoResult result, const uint32_t* srm_version) { + 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); + OPK_PackNullable_uint32_t(&msg, srm_version); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsAntiRollbackHWPresent_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10057) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Response(bool result) { + uint32_t api_value = 10057; /* from _tee10057 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ApplyCGMS_Request(ODK_Message* msg, uint8_t* cgms_field) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10058) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint8_t(msg, cgms_field); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ApplyCGMS_Response(OEMCryptoResult result) { + uint32_t api_value = 10058; /* from _tee10058 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsCGMS_AActive_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10059) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsCGMS_AActive_Response(bool result) { + uint32_t api_value = 10059; /* from _tee10059 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +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 != 10060) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_SupportsCGMS_A_Response(bool result) { + uint32_t api_value = 10060; /* from _tee10060 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_HasAnalogDisplay_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10061) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_HasAnalogDisplay_Response(bool result) { + uint32_t api_value = 10061; /* from _tee10061 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsAnalogDisplayActive_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10062) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsAnalogDisplayActive_Response(bool result) { + uint32_t api_value = 10062; /* from _tee10062 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_CanDisableAnalogDisplay_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10063) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_CanDisableAnalogDisplay_Response(bool result) { + 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); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_DisableAnalogDisplay_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10064) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_DisableAnalogDisplay_Response(bool result) { + uint32_t api_value = 10064; /* from _tee10064 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxBufferSizeForDecrypt_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10065) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxBufferSizeForDecrypt_Response(size_t result) { + uint32_t api_value = 10065; /* from _tee10065 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxOutputSizeForDecrypt_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10066) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Response(size_t result) { + uint32_t api_value = 10066; /* from _tee10066 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_IsClosedPlatform_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10067) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_IsClosedPlatform_Response(bool result) { + 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); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_CurrentHDCPCapability_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10068) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_CurrentHDCPCapability_Response( + OEMCrypto_HDCP_Capability result) { + uint32_t api_value = 10068; /* from _tee10068 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_HDCP_Capability(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxHDCPCapability_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10069) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxHDCPCapability_Response( + OEMCrypto_HDCP_Capability result) { + uint32_t api_value = 10069; /* from _tee10069 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_HDCP_Capability(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10070) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Response(size_t result) { + uint32_t api_value = 10070; /* from _tee10070 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_MaxSampleSize_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10071) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_MaxSampleSize_Response(size_t result) { + uint32_t api_value = 10071; /* from _tee10071 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_SupportedCertificates_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10072) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_SupportedCertificates_Response(uint32_t result) { + uint32_t api_value = 10072; /* from _tee10072 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ContentDecryptBypassesTA_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10073) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ContentDecryptBypassesTA_Response(bool result) { + uint32_t api_value = 10073; /* from _tee10073 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_bool(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_GetEncryptAndSignSize_Request(ODK_Message* msg, uint32_t* context, size_t* in_length, size_t** wrapped_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10042) + if (api_value != 10074) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1234,7 +1983,7 @@ void OPK_Unpack_GetEncryptAndSignSize_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetEncryptAndSignSize_Response( OEMCryptoResult result, const size_t* wrapped_length) { - uint32_t api_value = 10042; /* from _tee10042 */ + uint32_t api_value = 10074; /* from _tee10074 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1249,7 +1998,7 @@ void OPK_Unpack_EncryptAndSign_Request(ODK_Message* msg, uint32_t* context, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10043) + if (api_value != 10075) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1266,7 +2015,7 @@ void OPK_Unpack_EncryptAndSign_Request(ODK_Message* msg, uint32_t* context, ODK_Message OPK_Pack_EncryptAndSign_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10043; /* from _tee10043 */ + uint32_t api_value = 10075; /* from _tee10075 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -1285,7 +2034,7 @@ void OPK_Unpack_VerifyAndDecrypt_Request(ODK_Message* msg, uint32_t* context, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10044) + if (api_value != 10076) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1302,7 +2051,7 @@ void OPK_Unpack_VerifyAndDecrypt_Request(ODK_Message* msg, uint32_t* context, ODK_Message OPK_Pack_VerifyAndDecrypt_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10044; /* from _tee10044 */ + uint32_t api_value = 10076; /* from _tee10076 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -1317,17 +2066,17 @@ ODK_Message OPK_Pack_VerifyAndDecrypt_Response(OEMCryptoResult result, void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( ODK_Message* msg, uint8_t** wrapped, size_t* wrapped_length, - uint8_t** signature, uint8_t* iv, uint8_t** out) { + uint8_t** signature, uint8_t** iv, uint8_t** out) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10045) + if (api_value != 10077) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); OPK_Unpack_size_t(msg, wrapped_length); OPK_UnpackInPlace(msg, (uint8_t**)wrapped, OPK_FromSizeTPtr(wrapped_length)); OPK_UnpackNullable_uint8_t(msg, signature); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); *out = (uint8_t*)OPK_UnpackAlloc(msg, sizeof(uint8_t)); OPK_UnpackEOM(msg); OPK_SharedBuffer_FinalizeUnpacking(); @@ -1335,7 +2084,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Response( OEMCryptoResult result, const uint8_t* out) { - uint32_t api_value = 10045; /* from _tee10045 */ + uint32_t api_value = 10077; /* from _tee10077 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h index 065215a..cc54e97 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 @@ -12,6 +12,7 @@ #include "log_macros.h" #include "opk_serialization_base.h" +#include "wtpi_config_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" @@ -36,13 +37,13 @@ ODK_Message OPK_Pack_K1_GetKeySize_Response(OEMCryptoResult result, void OPK_Unpack_C1_AESCBCDecrypt_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, size_t* key_length, uint8_t** in_buffer, size_t* in_buffer_length, - uint8_t* iv, uint8_t** out_buffer); + uint8_t** iv, uint8_t** out_buffer); ODK_Message OPK_Pack_C1_AESCBCDecrypt_Response(OEMCryptoResult result, size_t in_buffer_length, const uint8_t* out_buffer); void OPK_Unpack_C1_AESCBCEncrypt_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, - uint8_t** in_buffer, size_t* in_buffer_length, uint8_t* iv, + uint8_t** in_buffer, size_t* in_buffer_length, uint8_t** iv, uint8_t** out_buffer); ODK_Message OPK_Pack_C1_AESCBCEncrypt_Response(OEMCryptoResult result, size_t in_buffer_length, @@ -75,13 +76,13 @@ ODK_Message OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Response( OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle); void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle, - uint8_t** enc_key, size_t* enc_key_length, uint8_t* iv, + uint8_t** enc_key, size_t* enc_key_length, uint8_t** iv, SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle); ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Response( OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle); void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle, - uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t* iv, + uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t** iv, WTPI_K1_SymmetricKey_Handle** out_mac_key_server, WTPI_K1_SymmetricKey_Handle** out_mac_key_client); ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Response( @@ -111,6 +112,12 @@ ODK_Message OPK_Pack_K1_UnwrapIntoKeyHandle_Response( void OPK_Unpack_K1_FreeKeyHandle_Request( ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle); ODK_Message OPK_Pack_K1_FreeKeyHandle_Response(OEMCryptoResult result); +void OPK_Unpack_K1_PrepareExternalKeyHandle_Request( + ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, + uint8_t** out_buffer, size_t** out_buffer_length); +ODK_Message OPK_Pack_K1_PrepareExternalKeyHandle_Response( + OEMCryptoResult result, const uint8_t* out_buffer, + const size_t* out_buffer_length); void OPK_Unpack_CreateAsymmetricKeyHandle_Request( ODK_Message* msg, uint8_t** input, size_t* input_length, AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle); @@ -175,11 +182,22 @@ void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg, size_t** signature_length); ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result, const size_t* signature_length); +void OPK_Unpack_GetSignatureHashAlgorithm_Request( + ODK_Message* msg, WTPI_AsymmetricKey_Handle* key, + AsymmetricKeyType* key_type, + OEMCrypto_SignatureHashAlgorithm** hash_algorithm); +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Response( + OEMCryptoResult result, + const OEMCrypto_SignatureHashAlgorithm* hash_algorithm); void OPK_Unpack_GetBootCertificateChain_Request(ODK_Message* msg, uint8_t** out, size_t** out_length); ODK_Message OPK_Pack_GetBootCertificateChain_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length); +void OPK_Unpack_GetMaxBootCertificateChainSize_Request(ODK_Message* msg, + size_t** out_length); +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Response( + OEMCryptoResult result, const size_t* out_length); void OPK_Unpack_GenerateRandomCertificateKeyPair_Request( ODK_Message* msg, AsymmetricKeyType** key_type, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, @@ -189,13 +207,34 @@ ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Response( const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, const size_t* public_key_length); -void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, - size_t* message_length, - uint8_t** signature, - size_t** signature_length); -ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( - OEMCryptoResult result, const uint8_t* signature, - const size_t* signature_length); +void OPK_Unpack_GetSignedCsrPayload_Request( + ODK_Message* msg, uint8_t** challenge, size_t* challenge_length, + uint8_t** encoded_device_info, size_t* encoded_device_info_length, + uint8_t** signed_csr_payload, size_t** signed_csr_payload_length); +ODK_Message OPK_Pack_GetSignedCsrPayload_Response( + OEMCryptoResult result, const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length); +void OPK_Unpack_MaxDeviceInfoSize_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxDeviceInfoSize_Response(size_t result); +void OPK_Unpack_GetDeviceInformation_Request(ODK_Message* msg, uint8_t** out, + size_t** out_length); +ODK_Message OPK_Pack_GetDeviceInformation_Response(OEMCryptoResult result, + const uint8_t* out, + const size_t* out_length); +void OPK_Unpack_BccKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, + size_t* message_length, + uint8_t** signature, + size_t** signature_length); +ODK_Message OPK_Pack_BccKeyCoseSign1_Response(OEMCryptoResult result, + const uint8_t* signature, + const size_t* signature_length); +void OPK_Unpack_GetMaxBccKeyCoseSign1Size_Request(ODK_Message* msg, + size_t** out_length); +ODK_Message OPK_Pack_GetMaxBccKeyCoseSign1Size_Response( + OEMCryptoResult result, const size_t* out_length); +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_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash); ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result, const uint32_t* initial_hash); @@ -219,6 +258,60 @@ ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result); void OPK_Unpack_GetClockType_Request(ODK_Message* msg); ODK_Message OPK_Pack_GetClockType_Response( OEMCrypto_Clock_Security_Level result); +void OPK_Unpack_GetSecurityLevel_Request(ODK_Message* msg); +ODK_Message OPK_Pack_GetSecurityLevel_Response(OEMCrypto_Security_Level result); +void OPK_Unpack_GetProvisioningMethod_Request(ODK_Message* msg); +ODK_Message OPK_Pack_GetProvisioningMethod_Response( + OEMCrypto_ProvisioningMethod result); +void OPK_Unpack_GetResourceRatingTier_Request(ODK_Message* msg); +ODK_Message OPK_Pack_GetResourceRatingTier_Response(uint32_t result); +void OPK_Unpack_IsTAAntiRollbackEnabled_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Response(OPK_FeatureStatus result); +void OPK_Unpack_IsProductionReady_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsProductionReady_Response(bool result); +void OPK_Unpack_GetWatermarkingSupport_Request(ODK_Message* msg); +ODK_Message OPK_Pack_GetWatermarkingSupport_Response( + OEMCrypto_WatermarkingSupport result); +void OPK_Unpack_GetCurrentSRMVersion_Request(ODK_Message* msg, + uint32_t** srm_version); +ODK_Message OPK_Pack_GetCurrentSRMVersion_Response(OEMCryptoResult result, + const uint32_t* srm_version); +void OPK_Unpack_IsAntiRollbackHWPresent_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Response(bool result); +void OPK_Unpack_ApplyCGMS_Request(ODK_Message* msg, uint8_t* cgms_field); +ODK_Message OPK_Pack_ApplyCGMS_Response(OEMCryptoResult result); +void OPK_Unpack_IsCGMS_AActive_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsCGMS_AActive_Response(bool result); +void OPK_Unpack_SupportsCGMS_A_Request(ODK_Message* msg); +ODK_Message OPK_Pack_SupportsCGMS_A_Response(bool result); +void OPK_Unpack_HasAnalogDisplay_Request(ODK_Message* msg); +ODK_Message OPK_Pack_HasAnalogDisplay_Response(bool result); +void OPK_Unpack_IsAnalogDisplayActive_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsAnalogDisplayActive_Response(bool result); +void OPK_Unpack_CanDisableAnalogDisplay_Request(ODK_Message* msg); +ODK_Message OPK_Pack_CanDisableAnalogDisplay_Response(bool result); +void OPK_Unpack_DisableAnalogDisplay_Request(ODK_Message* msg); +ODK_Message OPK_Pack_DisableAnalogDisplay_Response(bool result); +void OPK_Unpack_MaxBufferSizeForDecrypt_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxBufferSizeForDecrypt_Response(size_t result); +void OPK_Unpack_MaxOutputSizeForDecrypt_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Response(size_t result); +void OPK_Unpack_IsClosedPlatform_Request(ODK_Message* msg); +ODK_Message OPK_Pack_IsClosedPlatform_Response(bool result); +void OPK_Unpack_CurrentHDCPCapability_Request(ODK_Message* msg); +ODK_Message OPK_Pack_CurrentHDCPCapability_Response( + OEMCrypto_HDCP_Capability result); +void OPK_Unpack_MaxHDCPCapability_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxHDCPCapability_Response( + OEMCrypto_HDCP_Capability result); +void OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Response(size_t result); +void OPK_Unpack_MaxSampleSize_Request(ODK_Message* msg); +ODK_Message OPK_Pack_MaxSampleSize_Response(size_t result); +void OPK_Unpack_SupportedCertificates_Request(ODK_Message* msg); +ODK_Message OPK_Pack_SupportedCertificates_Response(uint32_t result); +void OPK_Unpack_ContentDecryptBypassesTA_Request(ODK_Message* msg); +ODK_Message OPK_Pack_ContentDecryptBypassesTA_Response(bool result); void OPK_Unpack_GetEncryptAndSignSize_Request(ODK_Message* msg, uint32_t* context, size_t* in_length, @@ -240,7 +333,7 @@ ODK_Message OPK_Pack_VerifyAndDecrypt_Response(OEMCryptoResult result, const size_t* out_length); void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( ODK_Message* msg, uint8_t** wrapped, size_t* wrapped_length, - uint8_t** signature, uint8_t* iv, uint8_t** out); + uint8_t** signature, uint8_t** iv, uint8_t** out); ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Response( OEMCryptoResult result, const uint8_t* out); #ifdef __cplusplus 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 67ba929..ae66c73 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 @@ -76,6 +76,31 @@ void OPK_Init_OEMCrypto_Clock_Security_Level( } } +void OPK_Init_OEMCrypto_Security_Level(OEMCrypto_Security_Level* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_Security_Level)); + } +} + +void OPK_Init_OEMCrypto_ProvisioningMethod(OEMCrypto_ProvisioningMethod* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_ProvisioningMethod)); + } +} + +void OPK_Init_OEMCrypto_WatermarkingSupport( + OEMCrypto_WatermarkingSupport* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_WatermarkingSupport)); + } +} + +void OPK_Init_OEMCrypto_HDCP_Capability(OEMCrypto_HDCP_Capability* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_HDCP_Capability)); + } +} + 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 040351e..ea9cf8b 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 @@ -21,6 +21,11 @@ void OPK_Init_RSA_Padding_Scheme(RSA_Padding_Scheme* obj); void OPK_Init_KeySize(KeySize* obj); void OPK_Init_OEMCrypto_Clock_Security_Level( OEMCrypto_Clock_Security_Level* obj); +void OPK_Init_OEMCrypto_Security_Level(OEMCrypto_Security_Level* obj); +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_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key, uint8_t** message, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_common.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_common.h new file mode 100644 index 0000000..6fdd918 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_common.h @@ -0,0 +1,25 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include +#include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_crypto_asymmetric_interface.h" + +using WtpiSymmetricKeyType = + std::remove_pointer::type; +const auto wtpi_symmetric_key_free = [](WtpiSymmetricKeyType* key) { + WTPI_K1_FreeKeyHandle(key); +}; +using WtpiSymmetricKeyPtr = + std::unique_ptr>; + +using WtpiAsymmetricKeyType = + std::remove_pointer::type; +const auto wtpi_asymmetric_key_free = [](WtpiAsymmetricKeyType* key) { + WTPI_FreeAsymmetricKeyHandle(key); +}; +using WtpiAsymmetricKeyPtr = + std::unique_ptr>; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp index 0063652..5f94f5f 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp @@ -52,14 +52,21 @@ 'sources': [ 'clock_interface_test.cpp', 'crypto_test.cpp', + 'provisioning_4_interface_test.cpp', 'generation_number_interface_test.cpp', 'ssl_util.cpp', + 'cose_util.cpp', 'test_rsa_key.cpp', '<(DEPTH)/linux/src/log.cpp', + '<(DEPTH)/util/src/string_conversions.cpp', ], 'includes': [ '../../../../util/libcrypto_dependency.gypi', ], + 'dependencies': [ + '../../../../third_party/cose-c.gyp:cose-c', + '../../../../third_party/open-dice.gyp:cbor', + ], }, ] } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_fused.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_fused.c new file mode 100644 index 0000000..e5d4b43 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_fused.c @@ -0,0 +1,11 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_provisioning_4_interface.h" + +OEMCryptoResult WTPI_GetDeviceFusedStatus(bool* is_fused) { + if (!is_fused) return OEMCrypto_ERROR_INVALID_CONTEXT; + *is_fused = false; + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_persistent_storage.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_persistent_storage.c new file mode 100644 index 0000000..f86e3fd --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_persistent_storage.c @@ -0,0 +1,54 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include + +#include "oemcrypto_check_macros.h" +#include "wtpi_persistent_storage.h" + +/* This implementation does not meet persistent storage reqiurements. It will + * pass most unit tests, but will fail under more realistic scenarios such as + * reboot. This will not work on an actual device. This file should be replaced + * with an implementation that stores data securely and persistently across + * reboots. + */ + +#define FAKE_PERSISTENT_DATA_MAX_SIZE 5 * 1024 +static uint8_t fake_persistent_data[FAKE_PERSISTENT_DATA_MAX_SIZE]; +static size_t pdata_used = 0; + +OEMCryptoResult WTPI_PrepareStoredPersistentData(void) { + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length) { + RETURN_INVALID_CONTEXT_IF_NULL(data); + RETURN_INVALID_CONTEXT_IF_NULL(data_length); + + if (pdata_used == 0) { + return OPK_ERROR_NO_PERSISTENT_DATA; + } + + if (*data_length < pdata_used) { + *data_length = pdata_used; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + memcpy(data, fake_persistent_data, pdata_used); + *data_length = pdata_used; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_StorePersistentData(const uint8_t* data, + size_t data_length) { + RETURN_INVALID_CONTEXT_IF_NULL(data); + + if (data_length > FAKE_PERSISTENT_DATA_MAX_SIZE) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(fake_persistent_data, 0, FAKE_PERSISTENT_DATA_MAX_SIZE); + memcpy(fake_persistent_data, data, data_length); + pdata_used = data_length; + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c index a9cc59b..892eed9 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c @@ -2,10 +2,11 @@ source code may only be used and distributed under the Widevine License Agreement. */ +#include "odk_attributes.h" #include "wtpi_secure_buffer_access_interface.h" /* Secure buffers are not supported by the test build. */ -OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset, +OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset UNUSED, uint8_t** out_addr) { if (secure == NULL || out_addr == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; diff --git a/oemcrypto/opk/ports/linux/Makefile b/oemcrypto/opk/ports/linux/Makefile new file mode 100644 index 0000000..2d10340 --- /dev/null +++ b/oemcrypto/opk/ports/linux/Makefile @@ -0,0 +1,66 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# $CDM_DIR must be defined as the path to the top level of the OPK release +ifndef CDM_DIR + $(error CDM_DIR is undefined) +endif + +.EXPORT_ALL_VARIABLES: + +ARCH := 64 +IS_ARM := 0 + +SOC_VENDOR := test +SOC_MODEL := test +TEE_OS := TEE_Simulator +TEE_VERSION := 0.0.0 +DEVICE_FORM_FACTOR := linux +IMPLEMENTER := your-name-here +PROVISIONING_METHOD ?= OEMCrypto_Keybox + +.PHONY: all +all: host ta + +.PHONY: ta +ta: oemcrypto_ta wtpi_ta + +.PHONY: host +host: oemcrypto_helloworld oemcrypto_unittests wtpi_unittests + +.PHONY: oemcrypto_ta +oemcrypto_ta: + +$(MAKE) -C ta/oemcrypto_ta + +.PHONY: wtpi_ta +wtpi_ta: + +$(MAKE) -C ta/wtpi_test_ta + +.PHONY: liboemcrypto +liboemcrypto: + +$(MAKE) -C host/liboemcrypto + +.PHONY: oemcrypto_helloworld +oemcrypto_helloworld: liboemcrypto + +$(MAKE) -C host/oemcrypto_helloworld + +.PHONY: oemcrypto_unittests +oemcrypto_unittests: liboemcrypto + +$(MAKE) -C host/oemcrypto_unittests + +.PHONY: wtpi_unittests +wtpi_unittests: + +$(MAKE) -C host/wtpi_unittests + +.PHONY: clean +clean: + +$(MAKE) -C ta/oemcrypto_ta clean + +$(MAKE) -C ta/wtpi_test_ta clean + +$(MAKE) -C host/liboemcrypto clean + +$(MAKE) -C host/oemcrypto_helloworld clean + +$(MAKE) -C host/oemcrypto_unittests clean + +$(MAKE) -C host/wtpi_unittests clean + diff --git a/oemcrypto/opk/ports/linux/README.md b/oemcrypto/opk/ports/linux/README.md new file mode 100644 index 0000000..f2ae772 --- /dev/null +++ b/oemcrypto/opk/ports/linux/README.md @@ -0,0 +1,105 @@ +# Linux example port + +This folder contains an end-to-end OPK example implementation using a simulated +REE/TEE boundary. Everything runs on the REE in Linux. + +** This implementation is for testing only! There is no reason for the provided +TA code to ever run in a non-secure environment in production. ** + +The following examples can be run +- `oemcrypto_unittests`: runs OEMCrypto API unit tests against the OEMCrypto TA +- `wtpi_unittests`: runs WTPI unit tests against the WTPI Test TA +- `oemcrypto_helloworld`: calls OEMCrypto_Initialize() to prove that the + serialization and execution works correctly between the REE and TEE. + +Before running each example, make sure the matching TEE simulator has been +started. The `oemcrypto_unittests` and `oemcrypto_helloworld` executables work +with tee_simulator_oemcrypto, and `wtpi_unittests` work with tee_simulator_wtpi. +Running in the background is sufficient, eg `./tee_simulator_oemcrypto &`. + +Instead of running in the TEE as a trusted app, the TA code is compiled as +a REE-side binary. The transport and shared memory interfaces of both host and +trusted apps are implemented using the POSIX shared memory and semaphore +libraries. The request and response messages are located in a shared memory +block and the request and response semaphores are used to synchronize the REE +and TEE communication by signaling when messages are available. + +# Build and run + +``` +$ make -C oemcrypto/opk/ports/linux all + +# Run simulated TEE with OEMCrypto TA +# If scripting around this, wait 1 second to allow TA time to start +$ ./oemcrypto_ta & + +# Capture pid +$ export TEE_SIM_PID=$! + +# Run host app +$ ./oemcrypto_helloworld + +# Stop TEE simulator +$ kill $TEE_SIM_PID +``` + +# Code organization + +``` +├── common +│   └── TOS implementation, POSIX resources +├── host +│   ├── liboemcrypto +│   │   └── builds liboemcrypto.so +│   ├── oemcrypto_helloworld +│   │   └── builds oemcrypto_helloworld executable +│   ├── oemcrypto_unittests +│   │   └── builds oemcrypto_unittests executable +│   └── wtpi_unittests +│   └── builds wtpi_unittests executable +├── rules.mk # Common build rules for all executables +└── ta + ├── common + │   ├── clock.cpp + │   ├── tee_simulator.cpp # Entry point for TAs + │   └── wtpi_impl + │   └── WTPI implementations specific to Linux test port + ├── oemcrypto_ta + │   └── builds simulated OEMCrypto TA + ├── gyp + │   └── internal GYP files + └── wtpi_test_ta + └── builds simulated WTPI Test TA + +``` + + +# OPK_SendMessage + +``` + +-----+ +-------------------+ +---------------+ +-------------------+ +-----+ + | REE | | ResponseSemaphore | | SharedMemory | | RequestSemaphore | | TEE | + +-----+ +-------------------+ +---------------+ +-------------------+ +-----+ + | | | | | + | | | | wait | + | | | |<-------------| + | | | | | + | write request | | | | + |----------------------------------->| | | + | | | | | + | post | | | | + |------------------------------------------------------->| | + | | | | | + | wait | | | | + |--------------->| | | | + | | | | | + | | | | read request | + | | |<---------------------------------| + | | | | | + | | | | post | + | |<-----------------------------------------------------| + | | | | | + | read response | | | | + |----------------------------------->| | | + | | | | | +``` diff --git a/oemcrypto/opk/ports/linux/common/posix_resources.h b/oemcrypto/opk/ports/linux/common/posix_resources.h new file mode 100644 index 0000000..80cee64 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/posix_resources.h @@ -0,0 +1,19 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef POSIX_RESOURCES__H_ +#define POSIX_RESOURCES__H_ + +#include "posix_services.h" + +// Global allocation of posix shared memory and semaphore +// resources for the transport and shared memory buffers + +typedef posix::SharedMemory<0> RequestResponseBlock; +typedef posix::SharedMemory<1> MailboxBlock; +typedef posix::SharedMemory<2> SerializationBlock; +typedef posix::Semaphore<0> RequestSemaphore; +typedef posix::Semaphore<1> ResponseSemaphore; + +#endif // POSIX_RESOURCES__H_ diff --git a/oemcrypto/opk/ports/linux/common/posix_services.h b/oemcrypto/opk/ports/linux/common/posix_services.h new file mode 100644 index 0000000..67242b2 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/posix_services.h @@ -0,0 +1,136 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#ifndef LINUX_IPC_POSIX_SERVICES_H_ +#define LINUX_IPC_POSIX_SERVICES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "log_macros.h" + +#ifndef WV_POSIX_RESOURCE_ID +# define WV_POSIX_RESOURCE_ID "tee-sim" +#endif + +namespace posix { + +// Services for shared memory and semaphores layered on the POSIX +// shm_* and sem_* functions + +// The Semaphore class is used to synchronize execution across process +// boundaries using the POSIX semaphore lib. N is an integer +// identifying the semaphore instance. +class Resource { + public: + Resource(const std::string& name, const std::string& posix_prefix) + : dev_path_("/dev/shm/" + posix_prefix + WV_POSIX_RESOURCE_ID + name), + posix_name_("/" WV_POSIX_RESOURCE_ID + name) {} + ~Resource() {} + + protected: + const std::string dev_path_; + const std::string posix_name_; +}; + +template +class Semaphore : public Resource { + public: + Semaphore() : Resource("opk-" + std::to_string(N), "sem."), sem_(nullptr) { + sem_ = sem_open(posix_name_.c_str(), O_CREAT, 0600, 0); + if (!sem_) { + LOGE("failed to open semaphore %s", posix_name_.c_str()); + } + } + + ~Semaphore() { + if (sem_) { + sem_close(sem_); + } + } + + void post() { + if (sem_) sem_post(sem_); + } + void wait() { + if (sem_) sem_wait(sem_); + } + + private: + sem_t* sem_; + + Semaphore(const Semaphore&) = delete; + void operator=(const Semaphore&) = delete; +}; + +// Manage blocks of shared memory across process boundaries using +// the POSIX shared memory functions. N is an integer identifying the +// shared memory block. + +template +class SharedMemory : public Resource { + public: + SharedMemory() + : Resource("opk-shm-" + std::to_string(N), ""), + fd_(-1), + address_(nullptr), + size_(0) { + Open(); + } + + ~SharedMemory() { Close(); } + + uint8_t* GetAddress() const { return address_; } + size_t GetSize() const { return size_; } + + bool Allocate(size_t size) { + if (fd_ == -1) { + return false; + } + if (ftruncate(fd_, size) == -1) { + LOGE("failed to set shared memory %s to size %zd: %s", dev_path_.c_str(), + size_, strerror(errno)); + return false; + } else { + address_ = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd_, 0); + if (address_ == nullptr) { + LOGE("mmap of size %zu failed: %s", size, strerror(errno)); + return false; + } else { + size_ = size; + } + } + return true; + } + + private: + int fd_; + uint8_t* address_; + size_t size_; + + void Open() { fd_ = shm_open(posix_name_.c_str(), O_CREAT | O_RDWR, 0600); } + + void Close() { + if (address_) { + munmap(address_, size_); + address_ = nullptr; + size_ = 0; + } + if (fd_ != -1) { + close(fd_); + fd_ = -1; + } + } + + SharedMemory(const SharedMemory&) = delete; + void operator=(const SharedMemory&) = delete; +}; +}; // namespace posix + +#endif /* LINUX_IPC_POSIX_SERVICES_H_ */ diff --git a/oemcrypto/opk/ports/linux/common/test/shared_memory_test.cpp b/oemcrypto/opk/ports/linux/common/test/shared_memory_test.cpp new file mode 100644 index 0000000..dfb3f3f --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/test/shared_memory_test.cpp @@ -0,0 +1,237 @@ +// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include +#include +#include + +#include "gtest/gtest.h" +#include "posix_services.h" +#include "tos_shared_memory_interface.h" +#include "tos_transport.h" + +using namespace posix; + +/* + * Entry point for the TEE process + */ +static void RunTEE(); + +int main(int argc, char** argv) { + if (argc == 2) { + if (*argv[1] == '1') { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } else { + RunTEE(); + } + } else { + if (fork()) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } else { + RunTEE(); + return 0; + } + } +} + +// utility functions shared by REE and TEE +static const unsigned KiB = 1024; +static const unsigned MiB = KiB * 1024; + +static uint8_t test_buffer[1024]; + +/* rand() seed for FillMemory/TestMemory, needs to be the same in REE and TEE */ +unsigned seed = 1234; + +/* Utility functions common to REE and TEE */ +void FillMemory(uint8_t* addr, size_t length, unsigned seed) { + std::srand(seed); + for (size_t i = 0; i < length; i++) { + addr[i] = static_cast(std::rand() & 0xff); + } +} + +bool TestMemory(uint8_t* addr, size_t length, unsigned seed) { + std::srand(seed); + for (size_t i = 0; i < length; i++) { + if (addr[i] != static_cast(std::rand() & 0xff)) { + return false; + } + } + return true; +} + +bool TestZero(uint8_t* addr, size_t length) { + for (size_t i = 0; i < length; i++) { + if (addr[i] != 0) { + return false; + } + } + return true; +} + +uint8_t* GetAddress() { return TOS_SharedMemory_GetAddress(); } +size_t GetSize() { return TOS_SharedMemory_GetSize(); } + +class SharedMemoryInterfaceTest : public testing::Test { + protected: + void SetUp() override {} + void TearDown() override {} +}; + +// Map sizes must meet the minum requirements +TEST_F(SharedMemoryInterfaceTest, AvailableSize) { + EXPECT_LE(2 * MiB + 32 * KiB, TOS_SharedMemory_AvailableSize()); +} + +// Make sure everything starts out initialized +TEST_F(SharedMemoryInterfaceTest, InitialState) { + EXPECT_EQ(nullptr, GetAddress()); + EXPECT_EQ(0, GetSize()); +} + +// Allocate a block with a 1 KiB size +TEST_F(SharedMemoryInterfaceTest, Allocate1KiBSize) { + size_t size = 1 * KiB; + TOS_SharedMemory_Allocate(size); + EXPECT_NE(nullptr, GetAddress()); + EXPECT_EQ(size, GetSize()); +} + +// Allocate the block with a 1 KiB size and make sure +// we can read/write it +TEST_F(SharedMemoryInterfaceTest, AllocateAllWith1KiBSizeAndRead) { + size_t size = 1 * KiB; + TOS_SharedMemory_Allocate(size); + FillMemory(GetAddress(), size, seed); + EXPECT_TRUE(TestMemory(GetAddress(), size, seed)); +} + +// Test releasing the block +TEST_F(SharedMemoryInterfaceTest, Release) { + size_t size = 1 * KiB; + TOS_SharedMemory_Allocate(size); + EXPECT_NE(nullptr, GetAddress()); + TOS_SharedMemory_Release(); + // all released? + EXPECT_EQ(nullptr, GetAddress()); + EXPECT_EQ(0, GetSize()); +} + +// Allocate a block with zero size +TEST_F(SharedMemoryInterfaceTest, AllocateZeroSize) { + size_t size = 0; + TOS_SharedMemory_Allocate(size); + EXPECT_NE(nullptr, GetAddress()); + EXPECT_EQ(size, GetSize()); +} + +// Allocate a block with the declared available size +TEST_F(SharedMemoryInterfaceTest, AllocateToAvailableSize) { + size_t size = TOS_SharedMemory_AvailableSize(); + TOS_SharedMemory_Allocate(size); + EXPECT_NE(nullptr, GetAddress()); + EXPECT_EQ(size, GetSize()); +} + +// Allocate a block and see if it will copy in from REE address on +// finalization. +TEST_F(SharedMemoryInterfaceTest, CopyIn) { + // fill test buffer + FillMemory(&test_buffer[0], sizeof(test_buffer), seed); + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + OPK_SharedMemory_CopyVector copy_vec = { + .address = &test_buffer[0], .offset = 0, .length = sizeof(test_buffer)}; + TOS_SharedMemory_Finalize(©_vec, 1, NULL, 0); + EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed)); +} + +// Allocate a block and ee if it will copy in from REE address on +// finalization at a non-zero offset. +TEST_F(SharedMemoryInterfaceTest, CopyInAtOffset) { + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + // Fill the test buffer and zero out the block + FillMemory(&test_buffer[0], sizeof(test_buffer), seed); + memset(GetAddress(), 0, sizeof(test_buffer)); + // copy in the first 512 bytes of the test_buffer into the + // shared memory block at offset 128, leaving the rest as zeros. + OPK_SharedMemory_CopyVector copy_vec = { + .address = &test_buffer[0], .offset = 128, .length = 512}; + TOS_SharedMemory_Finalize(©_vec, 1, NULL, 0); + EXPECT_TRUE(TestMemory(GetAddress() + 128, 512, seed)); + EXPECT_TRUE(TestZero(GetAddress(), 128)); + EXPECT_TRUE(TestZero(GetAddress() + 640, sizeof(test_buffer) - 640)); +} + +// Allocate a block with a non-NULL address and 1KiB size. See if it +// will copy out to REE address on finalization. +TEST_F(SharedMemoryInterfaceTest, CopyOut) { + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + // fill shared memory block + FillMemory(GetAddress(), sizeof(test_buffer), seed); + memset(&test_buffer[0], 0, sizeof(test_buffer)); + OPK_SharedMemory_CopyVector copy_vec = { + .address = &test_buffer[0], .offset = 0, .length = sizeof(test_buffer)}; + TOS_SharedMemory_Finalize(NULL, 0, ©_vec, 1); + EXPECT_TRUE(TestMemory(&test_buffer[0], sizeof(test_buffer), seed)); +} + +// Allocate a block and see if it will copy out from REE address on +// finalization at a non-zero offset. +TEST_F(SharedMemoryInterfaceTest, CopyOutAtOffset) { + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + // fill test buffer + FillMemory(&test_buffer[0], sizeof(test_buffer), seed); + + // Zero out the shared memory block, fill 512 bytes of the shared + // memory block at offset 128 and zero out the test_buffer + memset(GetAddress(), 0, sizeof(test_buffer)); + FillMemory(GetAddress() + 128, 512, seed); + memset(&test_buffer[0], 0, sizeof(test_buffer)); + + // copy out 512 bytes of the shared memory block at offset + // 128 into the test buffer + OPK_SharedMemory_CopyVector copy_vec = { + .address = &test_buffer[0], .offset = 128, .length = 512}; + TOS_SharedMemory_Finalize(NULL, 0, ©_vec, 1); + EXPECT_TRUE(TestMemory(&test_buffer[0], 512, seed)); + EXPECT_TRUE(TestZero(&test_buffer[512], sizeof(test_buffer) - 512)); +} + +// The IPC_SharedMemoryTests make sure that shared memory actually works +// across processes. + +class SharedMemoryIPCTest : public SharedMemoryInterfaceTest {}; + +// Test TEE->REE and REE->TEE on a block +TEST_F(SharedMemoryIPCTest, SharedAccess) { + Semaphore<0> begin; + Semaphore<1> ree_filled; + Semaphore<2> tee_filled; + Semaphore<3> ree_done; + begin.post(); + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + FillMemory(GetAddress(), sizeof(test_buffer), seed); + ree_filled.post(); + tee_filled.wait(); + EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed + 1)); + ree_done.post(); +} + +static void RunTEE() { + /* SharedAccess test */ + Semaphore<0> begin; + Semaphore<1> ree_filled; + Semaphore<2> tee_filled; + Semaphore<3> ree_done; + begin.wait(); + TOS_SharedMemory_Allocate(sizeof(test_buffer)); + ree_filled.wait(); + EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed)); + FillMemory(GetAddress(), sizeof(test_buffer), seed + 1); + tee_filled.post(); + ree_done.wait(); +} diff --git a/oemcrypto/opk/ports/linux/common/test/shared_memory_test.gyp b/oemcrypto/opk/ports/linux/common/test/shared_memory_test.gyp new file mode 100644 index 0000000..f5b4220 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/test/shared_memory_test.gyp @@ -0,0 +1,28 @@ +{ + 'includes' : { + '../../../../serialization/settings.gypi', + }, + 'target_defaults': { + 'include_dirs' : [ + '.', + '..', + '<(third_party_dir)/googletest/googletest/include', + ], + }, + 'targets' : [ + { + 'target_name': 'shared_memory_test', + 'type': 'executable', + 'sources': [ + 'shared_memory_test.cpp', + '../tos_shared_memory.cpp', + '../tos_logging.cpp', + ], + 'dependencies': [ + '<(third_party_dir)/googletest.gyp:gtest', + '<(serialization_dir)/tee/tee.gyp:opk_tee', + ], + 'libraries': ['-lrt', '-lpthread', '-ldl'], + }, + ] +} diff --git a/oemcrypto/opk/ports/linux/common/tos_logging.cpp b/oemcrypto/opk/ports/linux/common/tos_logging.cpp new file mode 100644 index 0000000..91e37b1 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/tos_logging.cpp @@ -0,0 +1,68 @@ +// +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +// This is an implementation of the tos_logging_interface for +// the linux trusted OS simulator port of OPK. For both the REE and +// TEE, it just writes the output to stderr. + +#include +#include +#include + +#include "tos_logging_interface.h" + +/******************************************************************* + * See "tos_logging_interface.h" for documentation of TOS_Log. + *******************************************************************/ + +static const char* LevelString(OPK_LogLevel level) { + switch (level) { + case OPK_LogLevel_Fatal: + return "FATAL"; + case OPK_LogLevel_Error: + return "ERROR"; + case OPK_LogLevel_Warning: + return "WARNING"; + case OPK_LogLevel_Info: + return "INFO"; + case OPK_LogLevel_Debug: + return "DEBUG"; + case OPK_LogLevel_Verbose: + return "VERBOSE"; + } + return ""; +} + +#ifdef __GNUC__ +__attribute__((format(printf, 5, 6))) +#endif +void TOS_Log(const char* file, const char* func, int line, + OPK_LogLevel level, const char* fmt, ...) { + /* + * By default, messages with levels at or higher than min_log_level + * will be logged. You can change the defaulit value of + * min_log_level here at compile time, or set the environment + * variable LINUX_IPC_LOG_LEVEL to the integer value of the minimum + * log level desired at runtime. + */ + static OPK_LogLevel min_log_level = OPK_LogLevel_Warning; + static bool set_log_level = true; + if (set_log_level) { + const char* env_level = getenv("LINUX_IPC_LOG_LEVEL"); + if (env_level) { + min_log_level = static_cast(atoi(env_level)); + } + set_log_level = false; + } + if (level >= min_log_level) { + va_list args; + va_start(args, fmt); + fprintf(stderr, "[%s:%s(%d):%s] ", LevelString(level), file, line, func); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } +} diff --git a/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c b/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c new file mode 100644 index 0000000..841c723 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c @@ -0,0 +1,34 @@ +/* + * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ +#include "opk_serialization_base.h" +#include "tos_secure_buffer_interface.h" + +/* + * The simulator doesn't do anything special with secure buffers, + * just pass the fields through unmodified + */ + +void TOS_SecureBuffer_Pack(ODK_Message* message, + const OEMCrypto_DestBufferDesc* obj) { + /* secure memory - pack handle, length, offset */ + OPK_Pack_uint64_t(message, + (const uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Pack_size_t(message, &obj->buffer.secure.secure_buffer_length); + OPK_Pack_size_t(message, &obj->buffer.secure.offset); +} + +void TOS_SecureBuffer_Unpack(ODK_Message* message, + OEMCrypto_DestBufferDesc* obj) { + /* secure memory - unpack handle, length, offset */ + OPK_Unpack_uint64_t(message, (uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Unpack_size_t(message, &obj->buffer.secure.secure_buffer_length); + OPK_Unpack_size_t(message, &obj->buffer.secure.offset); +} + +bool TOS_SecureBuffer_CheckSize(void* handle, size_t size) { + /* without real secure memory, there's nothing we can do here */ + return true; +} diff --git a/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp b/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp new file mode 100644 index 0000000..93d75e9 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp @@ -0,0 +1,88 @@ +// +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +// This is an implementation of the tos_shared_memory_interface for +// the linux trusted OS simulator port of OPK. It uses the +// posix_services.h implementation of shared memory which is based on +// the POSIX shared memory library. + +#include "posix_resources.h" +#include "tos_shared_memory_interface.h" + +using namespace posix; + +// shared memory for OEMCrypto parameters +static SerializationBlock* shared_memory_ = nullptr; + +/******************************************************************* + * See "tos_shared_memory_interface.h" for documentation + * of each of the TOS_SharedMemory interface functions below. + *******************************************************************/ + +bool TOS_SharedMemory_Allocate(size_t size) { + if (!shared_memory_) { + shared_memory_ = new SerializationBlock(); + if (!shared_memory_) { + LOGE("Failed to initialize shared memory"); + return false; + } + } + if (!shared_memory_->Allocate(size)) { + LOGE("Failed to allocate shared memory of size %zd bytes", size); + return false; + } + return true; +} + +void TOS_SharedMemory_Release(void) { + if (shared_memory_) { + delete shared_memory_; + shared_memory_ = nullptr; + } +} + +uint8_t* TOS_SharedMemory_GetAddress(void) { + return shared_memory_ ? shared_memory_->GetAddress() : nullptr; +} + +size_t TOS_SharedMemory_GetSize(void) { + return shared_memory_ ? shared_memory_->GetSize() : 0; +} + +void TOS_SharedMemory_Finalize(OPK_SharedMemory_CopyVector* in_vec, + size_t in_count, + OPK_SharedMemory_CopyVector* out_vec, + size_t out_count) { + if (shared_memory_) { + uint8_t* address = shared_memory_->GetAddress(); + if (address) { + for (size_t i = 0; i < in_count; i++) { + if (in_vec[i].address) { + memcpy(address + in_vec[i].offset, in_vec[i].address, + in_vec[i].length); + } + } + for (size_t i = 0; i < out_count; i++) { + if (out_vec[i].address) { + memcpy(out_vec[i].address, address + out_vec[i].offset, + out_vec[i].length); + } + } + } + } +} + +/* + * Provide enough shared memory for the max sample size for input and + * output shared memory buffers plus serialization buffer + */ +size_t TOS_SharedMemory_AvailableSize(void) { + const size_t KiB = 1024; + const size_t MiB = 1024 * KiB; + const size_t max_sample_size = 4 * MiB; + const size_t serialization_buffer_size = 32 * KiB; + return 2 * max_sample_size + serialization_buffer_size; +} diff --git a/oemcrypto/opk/ports/linux/common/tos_transport.cpp b/oemcrypto/opk/ports/linux/common/tos_transport.cpp new file mode 100644 index 0000000..8e39108 --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/tos_transport.cpp @@ -0,0 +1,155 @@ +// +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +// This is an implementation of the opk_transport_interface for the +// linux trusted OS simulator port of OPK. It uses the +// posix_services.h implementation of semaphores and shared memory +// which is based on the POSIX shared memory and semaphore libraries. + +#include "odk_message.h" +#include "posix_resources.h" +#include "tos_transport_interface.h" + +/******************************************************************* + * See "tos_transport_interface.h" for documentation of each of the + * TOS_ interface functions below. + *******************************************************************/ + +using namespace posix; + +// message request/response payload data +static RequestResponseBlock* shared_memory_ = nullptr; + +// mailbox containing the size of the payload +static MailboxBlock* mailbox_memory_ = nullptr; + +// post when a request message is ready +static RequestSemaphore* request_semaphore_ = nullptr; + +// post when a response message is ready +static ResponseSemaphore* response_semaphore_ = nullptr; + +static void ReleaseResources() { + if (shared_memory_) { + delete shared_memory_; + shared_memory_ = nullptr; + } + if (mailbox_memory_) { + delete mailbox_memory_; + mailbox_memory_ = nullptr; + } + if (request_semaphore_) { + delete request_semaphore_; + request_semaphore_ = nullptr; + } + if (response_semaphore_) { + delete response_semaphore_; + response_semaphore_ = nullptr; + } +} + +bool TOS_Transport_Initialize(void) { + if (!(shared_memory_ = new RequestResponseBlock()) || + !(shared_memory_->Allocate(OPK_TRANSPORT_MESSAGE_SIZE))) { + ReleaseResources(); + return false; + } + if (!(mailbox_memory_ = new MailboxBlock()) || + !(mailbox_memory_->Allocate(sizeof(uint32_t)))) { + ReleaseResources(); + return false; + } + if (!(request_semaphore_ = new RequestSemaphore())) { + ReleaseResources(); + return false; + } + if (!(response_semaphore_ = new ResponseSemaphore())) { + ReleaseResources(); + return false; + } + return true; +} + +void TOS_Transport_Terminate(void) { ReleaseResources(); } + +ODK_Message TOS_Transport_GetRequest() { + if (!shared_memory_) { + return ODK_Message_Create(nullptr, 0); + } else { + return ODK_Message_Create(shared_memory_->GetAddress(), + shared_memory_->GetSize()); + } +} + +ODK_Message TOS_Transport_GetResponse() { + /* Use the same shared memory block for request & response */ + return TOS_Transport_GetRequest(); +} + +void TOS_Transport_ReleaseMessage(ODK_Message* message) { + // resources are static, nothing to do here +} + +// Get the size of the message from the mailbox and return it +static uint32_t PeekSize(void) { + uint8_t* mailbox = mailbox_memory_->GetAddress(); + uint32_t message_size = (uint32_t)mailbox[0] | (uint32_t)mailbox[1] << 8 | + (uint32_t)mailbox[2] << 16 | + (uint32_t)mailbox[3] << 24; + return message_size; +} + +// Put the size of the message into the mailbox +static void PokeSize(uint32_t size) { + uint8_t* mailbox = mailbox_memory_->GetAddress(); + mailbox[0] = (uint8_t)(size); + mailbox[1] = (uint8_t)(size >> 8); + mailbox[2] = (uint8_t)(size >> 16); + mailbox[3] = (uint8_t)(size >> 24); +} + +// The request has been packed into the shared memory, all we need to +// do is poke the message size in the mailbox and post on the request +// semaphore, then wait for the response semaphore. The response will +// be in the shared memory by then, so return a response message +// constructed from the shared memory with the size in the mailbox. + +OPK_TransportStatus TOS_Transport_SendMessage(ODK_Message* request, + ODK_Message* response) { + PokeSize(static_cast(ODK_Message_GetSize(request))); + request_semaphore_->post(); + response_semaphore_->wait(); + *response = ODK_Message_Create(shared_memory_->GetAddress(), + shared_memory_->GetSize()); + ODK_Message_SetSize(response, PeekSize()); + return OPK_TRANSPORT_STATUS_OK; +} + +/******************************************************************** + * These are TOS functions only used by the tee_simulator, they are + * not an implementation of functions in the TOS transport interface. + ********************************************************************/ + +// Wait for the request until signaled. Then the request payload will +// be in the shared memory and the size in the mailbox. Create a +// request message from the payload data and return it. + +OPK_TransportStatus TOS_Transport_ReceiveRequest(ODK_Message* request) { + request_semaphore_->wait(); + *request = ODK_Message_Create(shared_memory_->GetAddress(), + shared_memory_->GetSize()); + ODK_Message_SetSize(request, PeekSize()); + return OPK_TRANSPORT_STATUS_OK; +} + +// The response has been packed into the shared memory. Put the message +// size in the mailbox then post on the response semaphore to send it. + +OPK_TransportStatus TOS_Transport_SendResponse(ODK_Message* response) { + PokeSize(static_cast(ODK_Message_GetSize(response))); + response_semaphore_->post(); + return OPK_TRANSPORT_STATUS_OK; +} diff --git a/oemcrypto/opk/ports/linux/common/tos_transport.h b/oemcrypto/opk/ports/linux/common/tos_transport.h new file mode 100644 index 0000000..d5e268b --- /dev/null +++ b/oemcrypto/opk/ports/linux/common/tos_transport.h @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef TOS_TRANSPORT_H_ +#define TOS_TRANSPORT_H_ + +#include "odk_message.h" +#include "tos_transport_interface.h" + +/******************************************************************* + * These functions are defined in the serialization adapter's + * tos_transport.c and tos_shared_memory.c to allow the tee simulator + * to use the transport and shared memory implementations. They are + * not part of the OPK OS interfaces. + *******************************************************************/ + +// Request is in the shared memory, create a response from the shared +// buffer and post on the response semaphore. +OPK_TransportStatus TOS_Transport_ReceiveRequest(ODK_Message* request); + +// Response is in the shared memory, post on the response +// semaphore to signal to the REE that it's ready. +OPK_TransportStatus TOS_Transport_SendResponse(ODK_Message* response); + +#endif // TOS_TRANSPORT_H_ diff --git a/oemcrypto/opk/ports/linux/host/liboemcrypto/Makefile b/oemcrypto/opk/ports/linux/host/liboemcrypto/Makefile new file mode 100644 index 0000000..3337c3b --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/liboemcrypto/Makefile @@ -0,0 +1,39 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This file expects the following definitions +# - CDM_DIR: absolute path to top of CDM repo. + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project).so + +# All file locations are relative to the $CDM_DIR path. +OPK_REPO_TOP := +include $(srcdir)/oemcrypto/opk/build/ree-sources.mk + +srcs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp \ + $(liboemcrypto_sources) \ + +incs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/include \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto \ + $(liboemcrypto_includes) \ + +cflags += \ + -DWV_POSIX_RESOURCE_ID=\"oemcrypto_ta\" \ + +ldflags = -lpthread -shared -lrt + +include ../../rules.mk + diff --git a/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp b/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp new file mode 100644 index 0000000..f7823eb --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp @@ -0,0 +1,17 @@ +// +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "opk_init.h" + +// When liboemcrypto is loaded, initialize the OPK + +static void __attribute__((constructor)) Initialize_On_Load(void) { + OPK_Initialize(); +} + +static void __attribute__((destructor)) Terminate_On_Close(void) { + OPK_Terminate(); +} diff --git a/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/Makefile b/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/Makefile new file mode 100644 index 0000000..7e93f6c --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This file expects the following definitions +# - CDM_DIR: absolute path to top of CDM repo. + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project) + +# All file locations are relative to the $CDM_DIR path. +OPK_REPO_TOP := +include $(srcdir)/oemcrypto/opk/build/ree-sources.mk + +srcs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c \ + +incs += \ + $(OPK_REPO_TOP)/oemcrypto/include \ + +ldflags = \ + -lrt -ldl -L$(builddir)/../liboemcrypto/ -loemcrypto \ + +include ../../rules.mk + + diff --git a/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c b/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c new file mode 100644 index 0000000..0587c21 --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c @@ -0,0 +1,20 @@ +/* + * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#include +#include "OEMCryptoCENC.h" + +int main(void) { + printf("Hello world\n"); + + OEMCryptoResult res; + res = OEMCrypto_Initialize(); + printf("OEMCrypto_Initialize() returned %d", res); + + OEMCrypto_Terminate(); + + return 0; +} diff --git a/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/Makefile b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/Makefile new file mode 100644 index 0000000..0bba40e --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/Makefile @@ -0,0 +1,38 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This file expects the following definitions +# - CDM_DIR: absolute path to top of CDM repo. +# - TEEC_EXPORT: absolute path to libteec.so +# - PLATFORM: optee platform name, eg vexpress-qemu_virt + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project) + +# All file locations are relative to the $CDM_DIR path. +OPK_REPO_TOP := +include $(srcdir)/oemcrypto/opk/build/ree-sources.mk + +srcs += \ + $(oemcrypto_unittests_sources) \ + +incs += \ + $(oemcrypto_unittests_includes) \ + +ldflags = \ + -lpthread \ + -lrt \ + -L$(builddir)/../liboemcrypto/ -loemcrypto \ + -static-libstdc++ \ + +cppflags += \ + -DOPENSSL_NO_ASM \ + -Wnon-virtual-dtor \ + +include ../../rules.mk diff --git a/oemcrypto/opk/ports/linux/host/wtpi_unittests/Makefile b/oemcrypto/opk/ports/linux/host/wtpi_unittests/Makefile new file mode 100644 index 0000000..b32f676 --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/wtpi_unittests/Makefile @@ -0,0 +1,51 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This file expects the following definitions +# - CDM_DIR: absolute path to top of CDM repo. +# - PLATFORM: optee platform name, eg vexpress-qemu_virt + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project) + +# All file locations are relative to the $CDM_DIR path. +OPK_REPO_TOP := +include $(srcdir)/oemcrypto/opk/build/ree-sources.mk + +srcs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_main.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.c \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.c \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.c \ + $(wtpi_unittests_sources) \ + +incs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/wtpi_test_ta/include \ + $(wtpi_unittests_includes) \ + +ldflags = \ + -lpthread \ + -lrt \ + -static-libstdc++ \ + +cppflags += \ + -DOPENSSL_NO_ASM \ + -DWV_POSIX_RESOURCE_ID=\"wtpi_test_ta\" \ + -Wnon-virtual-dtor \ + -DCOSE_C_USE_OPENSSL \ + -include 'cstdlib' \ + '-DEVP_aes_128_ccm()=EVP_aes_128_gcm()' \ + '-DEVP_aes_256_ccm()=EVP_aes_256_gcm()' \ + '-DEVP_aes_192_ccm()=EVP_aes_192_gcm()' \ + '-DEVP_CTRL_CCM_SET_L=0x14' \ + '-DEVP_CTRL_CCM_GET_TAG=EVP_CTRL_GCM_GET_TAG' \ + '-DEVP_CTRL_CCM_SET_TAG=EVP_CTRL_GCM_SET_TAG' \ + +include ../../rules.mk diff --git a/oemcrypto/opk/ports/linux/liboemcrypto.gyp b/oemcrypto/opk/ports/linux/liboemcrypto.gyp new file mode 100644 index 0000000..f44feb0 --- /dev/null +++ b/oemcrypto/opk/ports/linux/liboemcrypto.gyp @@ -0,0 +1,31 @@ +{ + 'variables': { + 'serialization_adapter_dir' : 'common', + }, + 'includes' : [ + '../../serialization/settings.gypi', + ], + 'targets' : [ + { + 'toolsets' : [ 'target' ], + 'target_name': 'liboemcrypto', + 'type': 'shared_library', + 'sources': [ + 'host/liboemcrypto/load_library.cpp', + '<(serialization_adapter_dir)/tos_logging.cpp', + '<(serialization_adapter_dir)/tos_secure_buffers.c', + '<(serialization_adapter_dir)/tos_shared_memory.cpp', + '<(serialization_adapter_dir)/tos_transport.cpp', + ], + 'link_settings': { + 'libraries': [ + '-lpthread', + '-lrt' + ], + }, + 'dependencies': [ + '<(ree_dir)/ree.gyp:opk_ree', + ], + }, + ] +} diff --git a/oemcrypto/opk/ports/linux/oemcrypto_tee_simulator.gyp b/oemcrypto/opk/ports/linux/oemcrypto_tee_simulator.gyp new file mode 100644 index 0000000..43b5f05 --- /dev/null +++ b/oemcrypto/opk/ports/linux/oemcrypto_tee_simulator.gyp @@ -0,0 +1,74 @@ +{ + 'variables': { + # Override the variables below for the location of various gyp files. + 'privacy_crypto_impl%': 'boringssl', + 'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto', + 'boringssl_libssl_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:ssl', + 'gtest_dependency%': '<(DEPTH)/third_party/googletest.gyp:gtest', + 'gmock_dependency%': '<(DEPTH)/third_party/googletest.gyp:gmock', + 'oemcrypto_dir%': '<(DEPTH)/oemcrypto', + 'util_dir%': '<(DEPTH)/util', + 'platform_specific_dir%': '<(DEPTH)/linux/src', + 'serialization_adapter_dir' : 'common', + }, + 'includes' : { + '../../serialization/settings.gypi', + }, + 'target_defaults': { + 'include_dirs' : [ + '.', + '<(serialization_adapter_dir)', + '<(serialization_dir)/tee/include', + '<(util_dir)/include', + ], + }, + 'targets' : [ + { + 'target_name': 'tee_simulator_oec_ref', + 'type': 'executable', + 'sources': [ + 'ta/common/clock.cpp', + 'ta/common/tee_simulator.cpp', + '<(platform_specific_dir)/file_store.cpp', + '<(platform_specific_dir)/log.cpp', + '<(serialization_adapter_dir)/tos_logging.cpp', + '<(serialization_adapter_dir)/tos_secure_buffers.c', + '<(serialization_adapter_dir)/tos_shared_memory.cpp', + '<(serialization_adapter_dir)/tos_transport.cpp', + '<(util_dir)/src/platform.cpp', + '<(util_dir)/src/rw_lock.cpp', + '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', + ], + 'dependencies': [ + '<(serialization_dir)/tee/tee.gyp:opk_tee', + '../../../testbed/oec_testbed.gyp:oec_testbed', + '../../../testbed/oec_testbed.gyp:utils_props_and_logs', + ], + 'libraries': ['-lrt', '-lpthread', '-ldl'], + }, + { + 'target_name': 'tee_simulator_ta', + 'type': 'executable', + 'sources': [ + 'ta/common/clock.cpp', + 'ta/common/tee_simulator.cpp', + '<(platform_specific_dir)/file_store.cpp', + '<(platform_specific_dir)/log.cpp', + '<(serialization_adapter_dir)/tos_logging.cpp', + '<(serialization_adapter_dir)/tos_secure_buffers.c', + '<(serialization_adapter_dir)/tos_shared_memory.cpp', + '<(serialization_adapter_dir)/tos_transport.cpp', + '<(util_dir)/src/platform.cpp', + '<(util_dir)/src/rw_lock.cpp', + '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', + ], + 'dependencies': [ + '<(serialization_dir)/tee/tee.gyp:opk_tee', + '<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc', + ], + 'libraries': ['-lrt', '-lpthread', '-ldl'], + }, + ] +} diff --git a/oemcrypto/opk/ports/linux/rules.mk b/oemcrypto/opk/ports/linux/rules.mk new file mode 100644 index 0000000..c72afb1 --- /dev/null +++ b/oemcrypto/opk/ports/linux/rules.mk @@ -0,0 +1,84 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This makefile is a simple set of rules for compiling Linux example REE/TEE. +# +# Inputs: +# - srcdir: Relative path from parent Makefile to source file directory, eg top +# of repo. +# - builddir: Relative path from parent Makefile to destination directory. +# - srcs: List of source .c/.cpp/.cc/.S files. All entries in $(srcs) +# must be relative to $(srcdir) +# - incs: List of include paths. Must be relative to $(srcdir). +# - CROSS_COMPILE: prefix for gcc, eg arm-none-gnueabihf- +# +# Can optionally provide additional ldflags, cflags, cppflags, and global-incs + +ifneq ($V,1) +q := @ +cmd-echo := true +cmd-echo-silent := echo +else +q := +cmd-echo := echo +cmd-echo-silent := true +endif + +cc := $(CROSS_COMPILE)gcc +cxx := $(CROSS_COMPILE)g++ + +ssrc := $(patsubst %.S, %.o, $(filter %.S, $(srcs))) +csrc := $(patsubst %.c, %.o, $(filter %.c, $(srcs))) +cppsrc := $(patsubst %.cpp, %.o, $(filter %.cpp, $(srcs))) +ccsrc := $(patsubst %.cc, %.o, $(filter %.cc, $(srcs))) +objs = $(sort $(addprefix $(builddir), $(csrc) $(cppsrc) $(ccsrc) $(ssrc))) + +includes += $(addprefix -I, $(addprefix $(srcdir)/, $(incs)) $(global-incs)) + +cflags += -Wall \ + -Werror \ + -fPIC \ + $(includes) \ + +cflags_c += $(cflags) \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L \ + -fno-inline + +cppflags += $(cflags) \ + $(CPPFLAGS) \ + +all: $(builddir)$(output) + +$(builddir)$(output): $(objs) + @$(cmd-echo-silent) ' LD $@' + ${q}$(cxx) -o $@ $(objs) $(ldadd) $(ldflags) + +.PHONY: clean +clean: + @$(cmd-echo-silent) ' CLEAN $(builddir)' + ${q}rm -f $(objs) $(output) + @if [ -d $(builddir) ]; then rm -r $(builddir); fi + +$(builddir)%.o: $(srcdir)%.c + ${q}mkdir -p $(shell dirname $@) + @$(cmd-echo-silent) ' CC $@' + ${q}$(cc) $(cflags_c) -c $< -o $@ + +$(builddir)%.o: $(srcdir)%.cc + ${q}mkdir -p $(shell dirname $@) + @$(cmd-echo-silent) ' CPP $@' + ${q}$(cxx) $(cppflags) -c $< -o $@ + +$(builddir)%.o: $(srcdir)%.cpp + ${q}mkdir -p $(shell dirname $@) + @$(cmd-echo-silent) ' CPP $@' + ${q}$(cxx) $(cppflags) -c $< -o $@ + +$(builddir)%.o: $(srcdir)%.S + ${q}mkdir -p $(shell dirname $@) + @$(cmd-echo-silent) ' CC $@' + ${q}$(cc) $(cflags_c) -c $< -o $@ diff --git a/oemcrypto/opk/ports/linux/scripts/build.sh b/oemcrypto/opk/ports/linux/scripts/build.sh new file mode 100755 index 0000000..c3c61a6 --- /dev/null +++ b/oemcrypto/opk/ports/linux/scripts/build.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Builds OEMCrypto unit tests and WTPI unit tests, along with TEE simulators for +# each. + +if [ -z "$CDM_DIR" ]; then + echo "CDM_DIR must be set to the top of the repo" + exit +fi + +build_linux() { + pushd $CDM_DIR + make -j$(nproc) -C ./oemcrypto/opk/ports/linux all $1 + popd +} + +# See Makefiles in oemcrypto_ta and wtpi_test_ta for how the PROVISIONING_METHOD +# var is used +build_linux PROVISIONING_METHOD=OEMCrypto_Keybox + +# build_linux PROVISIONING_METHOD=OEMCrypto_BootCertificateChain diff --git a/oemcrypto/opk/ports/linux/scripts/run.sh b/oemcrypto/opk/ports/linux/scripts/run.sh new file mode 100755 index 0000000..b4ecae4 --- /dev/null +++ b/oemcrypto/opk/ports/linux/scripts/run.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Runs OEMCrypto unit tests and WTPI unit tests, assuming they were built using +# the Makefile provided. +# Race conditions sometimes occur, causing the executables to hang at the +# beginning of each test suite, so don't rely on these for CI/CD or production. + +if [ -z "$CDM_DIR" ]; then + echo "CDM_DIR must be set to the top of the repo" + exit +fi + +kill_ta_simulators() { + oemcrypto_ta_pid=$(ps aux | grep '[o]emcrypto_ta' | awk '{print $2}') + wtpi_ta_pid=$(ps aux | grep '[w]tpi_test_ta' | awk '{print $2}') + + if [ -n "$oemcrypto_ta_pid" ]; then + echo "Terminating OEMCrypto TA simulator (PID $oemcrypto_ta_pid)" + kill $oemcrypto_ta_pid + fi + + if [ -n "$wtpi_ta_pid" ]; then + echo "Terminating WTPI Test TA simulator (PID $wtpi_ta_pid)" + kill $wtpi_ta_pid + fi +} + +run_tests() { + builddir=$CDM_DIR/out/linux + + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$builddir/liboemcrypto + + $builddir/oemcrypto_ta/oemcrypto_ta & + $builddir/wtpi_test_ta/wtpi_test_ta & + + trap kill_ta_simulators EXIT + + sleep 1 + wtpi_ta_pid=$(ps aux | grep '[w]tpi_test_ta' | awk '{print $2}') + if [[ -f "/proc/$wtpi_ta_pid/stat" ]]; then + $builddir/wtpi_unittests/wtpi_unittests --gtest_filter="-*Reboot*" + else + echo "WTPI TA simulator did not start." + FINAL_RESULT=43 + fi + + oemcrypto_ta_pid=$(ps aux | grep '[o]emcrypto_ta' | awk '{print $2}') + if [[ -f "/proc/$oemcrypto_ta_pid/stat" ]]; then + $builddir/oemcrypto_unittests/oemcrypto_unittests + else + echo "OEMCrypto TA simulator did not start." + FINAL_RESULT=43 + fi +} + +run_tests + +exit $FINAL_RESULT diff --git a/oemcrypto/opk/ports/linux/ta/common/clock.cpp b/oemcrypto/opk/ports/linux/ta/common/clock.cpp new file mode 100644 index 0000000..1eda0cb --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/clock.cpp @@ -0,0 +1,20 @@ +// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Clock - implemented using the standard linux time library + +#include "clock.h" + +#include + +namespace wvutil { + +int64_t Clock::GetCurrentTime() { + struct timeval tv; + tv.tv_sec = tv.tv_usec = 0; + gettimeofday(&tv, nullptr); + return tv.tv_sec; +} + +} // namespace wvutil diff --git a/oemcrypto/opk/ports/linux/ta/common/opk_config.h b/oemcrypto/opk/ports/linux/ta/common/opk_config.h new file mode 100644 index 0000000..2ca0aa8 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/opk_config.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef _OPK_CONFIG_H_ +#define _OPK_CONFIG_H_ + +#ifndef OPK_CONFIG_SECURITY_LEVEL +# define OPK_CONFIG_SECURITY_LEVEL OEMCrypto_Level3 +#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 1 * 1024 * 1024 +#endif + +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO +# define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO 500 * 1024 +#endif + +#ifndef OPK_CONFIG_MAX_SAMPLE_SIZE +# 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 | \ + OEMCrypto_Supports_ECC_secp256r1) +#endif + +#ifndef MAX_NUMBER_OF_ASYMMETRIC_KEYS +# define MAX_NUMBER_OF_ASYMMETRIC_KEYS 8 +#endif + +// Use defaults from wtpi_reference for the rest +#include "config/default.h" + +#endif diff --git a/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp b/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp new file mode 100644 index 0000000..258f391 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ +#include +#include +#include +#include + +#include "log_macros.h" +#include "odk_message.h" +#include "opk_dispatcher.h" +#include "opk_init.h" +#include "string.h" +#include "tos_transport.h" +#include "tos_transport_interface.h" + +static pthread_t main_thread_tid; +static bool thread_running = false; + +void signalHandler(int signum) { + // TODO(fredgc): this doesn't actually kill anything because the main loop is + // stuck waiting for a new message. + thread_running = false; + // This exits, but then we skip the OPK_Terminate call. + exit(0); +} + +// The request message data must be copied into a local buffer +// so the contents can't be modified while being parsed. +static uint8_t local_buffer[OPK_TRANSPORT_MESSAGE_SIZE]; + +static void* MainLoop(void* arg) { + OPK_Initialize(); + thread_running = true; + while (thread_running) { + ODK_Message request, response; + OPK_TransportStatus transport_status = + TOS_Transport_ReceiveRequest(&request); + if (transport_status != OPK_TRANSPORT_STATUS_OK) { + LOGE("Receive request failed: status=%s", + OPK_TransportStatus_Str(transport_status)); + continue; + } + // + // !! IMPORTANT NOTE !! + // The request payload buffer MUST be copied out to TEE local + // storage so it can't be tampered with while being + // parsed. Failure to do so could introduce security + // vulnerabilities. + // + size_t payload_size = ODK_Message_GetSize(&request); + memcpy(local_buffer, ODK_Message_GetBase(&request), payload_size); + ODK_Message safe_request = + ODK_Message_Create(local_buffer, sizeof(local_buffer)); + ODK_Message_SetSize(&safe_request, payload_size); + + ODK_MessageStatus message_status = + OPK_DispatchMessage(&safe_request, &response); + if (message_status != MESSAGE_STATUS_OK) { + LOGE("Dispatch failed: status=%s", OPK_MessageStatus_Str(message_status)); + } + transport_status = TOS_Transport_SendResponse(&response); + if (transport_status != OPK_TRANSPORT_STATUS_OK) { + LOGE("Send response failed: status=%s", + OPK_TransportStatus_Str(transport_status)); + continue; + } + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + } + OPK_Terminate(); + return nullptr; +} + +int main(int argc, char** argv) { + pthread_attr_t p_attr; + + int result = pthread_attr_init(&p_attr); + if (result != 0) { + LOGF("Failed pthread_attr_init: %s", strerror(errno)); + abort(); + } + + LOGI("Reset shared resource state"); + system("rm /dev/shm/*opk*"); + + LOGI("Starting the main loop thread"); + result = pthread_create(&main_thread_tid, &p_attr, &MainLoop, nullptr); + if (result != 0) { + LOGF("Failed to spawn a thread: %s", strerror(errno)); + abort(); + } + signal(SIGTERM, signalHandler); + LOGI("Main is waiting for the main loop thread to exit"); + void* retval; + result = pthread_join(main_thread_tid, &retval); + if (result != 0) { + LOGF("Failed to join main thread: %s", strerror(errno)); + abort(); + } + return 0; +} diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.c b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.c new file mode 100644 index 0000000..b5d855d --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.c @@ -0,0 +1,227 @@ +/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#include "layer2_crypto_key_table.h" + +#include +#include + +#include "opk_config.h" +#include "wtpi_abort_interface.h" + +/****************************************************************************** + * This is a test implementation of the simulation of the crypto key table which + * is supported by hardware. A doubly linked list and a FIFO eviction algorithm + * is implemented. When a key gets evicted, a callback is triggered to notify + * the key holder in the upper layer, presumably, crypto and key management + * layer 2. + ******************************************************************************/ + +/* + * A minimum number of 4 key slots is required in order to successfully open a + * session and load the encryption and mac keys. + */ +#if MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES < 4 +# error "MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES must be at least 4" +#endif + +#define INDEX_OUT_OF_BOUND MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES + +typedef struct k2_symmetric_key { + SymmetricKeyType key_type; + uint8_t aes_key[MAX_SYMMETRIC_KEY_SIZE]; + KeySize size; +} K2_SymmetricKey; + +typedef struct k2_key_table_entry { + K2_SymmetricKey key; + bool is_used; + uint32_t prev; + uint32_t next; +} K2_KeyTableEntry; + +typedef struct k2_key_table { + K2_KeyTableEntry entries[MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES]; + uint32_t first_free, last_free; + uint32_t first_used, last_used; + OEMCryptoResult (*eviction_callback)(uint32_t); +} K2_KeyTable; + +static K2_KeyTable gKeyTable; + +/** Move key |index| from the free queue to the used queue. */ +static void MoveToUsed(K2_KeyTable* table, uint32_t index) { + if (!table || !K2_IsIndexValid(index)) return; + if (table->entries[index].is_used) return; + + // remove from free queue and update first_free or last_free as needed + if (table->entries[index].prev != INDEX_OUT_OF_BOUND) { + table->entries[table->entries[index].prev].next = + table->entries[index].next; + } + if (table->entries[index].next != INDEX_OUT_OF_BOUND) { + table->entries[table->entries[index].next].prev = + table->entries[index].prev; + } + if (index == table->first_free) { + table->first_free = table->entries[table->first_free].next; + } + if (index == table->last_free) { + table->last_free = table->entries[table->last_free].prev; + } + + // add to the tail of used queue + if (table->last_used == INDEX_OUT_OF_BOUND) { + table->first_used = index; + table->entries[index].prev = INDEX_OUT_OF_BOUND; + } else { + table->entries[table->last_used].next = index; + table->entries[index].prev = table->last_used; + } + table->entries[index].is_used = true; + table->entries[index].next = INDEX_OUT_OF_BOUND; + table->last_used = index; +} + +/** Move key |index| from the used queue to the free queue. */ +static void MoveToFree(K2_KeyTable* table, uint32_t index) { + if (!table || !K2_IsIndexValid(index)) return; + if (!table->entries[index].is_used) return; + + memset(&table->entries[index].key, 0, sizeof(table->entries[index].key)); + + // remove from used queue and update first_used or last_used as needed + if (table->entries[index].prev != INDEX_OUT_OF_BOUND) { + table->entries[table->entries[index].prev].next = + table->entries[index].next; + } + if (table->entries[index].next != INDEX_OUT_OF_BOUND) { + table->entries[table->entries[index].next].prev = + table->entries[index].prev; + } + if (index == table->first_used) { + table->first_used = table->entries[table->first_used].next; + } + if (index == table->last_used) { + table->last_used = table->entries[table->last_used].prev; + } + + // add to the tail of free queue + if (table->last_free == INDEX_OUT_OF_BOUND) { + table->first_free = index; + table->entries[index].prev = INDEX_OUT_OF_BOUND; + } else { + table->entries[table->last_free].next = index; + table->entries[index].prev = table->last_free; + } + table->entries[index].is_used = false; + table->entries[index].next = INDEX_OUT_OF_BOUND; + table->last_free = index; +} + +static OEMCryptoResult GetNextAvailable(K2_KeyTable* table, uint32_t* index) { + if (table == NULL || index == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *index = INDEX_OUT_OF_BOUND; + if (table->first_free < INDEX_OUT_OF_BOUND) { + *index = table->first_free; + return OEMCrypto_SUCCESS; + } + // eviction: key and handle removal is done in callback + uint32_t eviction = table->first_used; + if (!K2_IsIndexValid(eviction)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + OEMCryptoResult result = table->eviction_callback(eviction); + if (result != OEMCrypto_SUCCESS) return result; + MoveToFree(table, eviction); + *index = eviction; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult K2_InitializeKeyTable(void) { + for (uint32_t i = 0; i < MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES; ++i) { + memset(&gKeyTable.entries[i].key, 0, sizeof(gKeyTable.entries[i].key)); + gKeyTable.entries[i].next = i + 1; + if (i == 0) { + gKeyTable.entries[i].prev = INDEX_OUT_OF_BOUND; + } else { + gKeyTable.entries[i].prev = i - 1; + } + gKeyTable.entries[i].is_used = false; + } + gKeyTable.first_free = 0; + gKeyTable.last_free = INDEX_OUT_OF_BOUND - 1; + gKeyTable.first_used = INDEX_OUT_OF_BOUND; + gKeyTable.last_used = INDEX_OUT_OF_BOUND; + gKeyTable.eviction_callback = NULL; + return OEMCrypto_SUCCESS; +} + +bool K2_IsIndexValid(uint32_t index) { return index < INDEX_OUT_OF_BOUND; } + +bool K2_IsKeyValid(uint32_t index) { + if (!K2_IsIndexValid(index)) return false; + if (!gKeyTable.entries[index].is_used) return false; + K2_SymmetricKey* key = &gKeyTable.entries[index].key; + switch (key->key_type) { + case CONTENT_KEY: + // We cheat a little here. We also call generic crypto keys "content + // keys", even though some of them are 256 bit HMAC keys. + return key->size == KEY_SIZE_128 || key->size == KEY_SIZE_256; + case ENTITLEMENT_KEY: + case MAC_KEY_SERVER: + case MAC_KEY_CLIENT: + return key->size == KEY_SIZE_256; + case ENCRYPTION_KEY: + case DERIVING_KEY: + return key->size == KEY_SIZE_128; + } + return false; +} + +void K2_SetEvictionCallback(OEMCryptoResult (*callback)(uint32_t)) { + gKeyTable.eviction_callback = callback; +} + +uint8_t* K2_GetKey(uint32_t index) { + ABORT_IF(!K2_IsKeyValid(index), "Invalid key."); + return gKeyTable.entries[index].key.aes_key; +} + +KeySize K2_GetKeySize(uint32_t index) { + ABORT_IF(!K2_IsKeyValid(index), "Invalid key."); + return gKeyTable.entries[index].key.size; +} + +SymmetricKeyType K2_GetKeyType(uint32_t index) { + ABORT_IF(!K2_IsKeyValid(index), "Invalid key."); + return gKeyTable.entries[index].key.key_type; +} + +OEMCryptoResult K2_AddKey(const uint8_t* key_bytes, size_t size, + SymmetricKeyType key_type, uint32_t* index) { + if (key_bytes == NULL || size == 0 || index == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint32_t next = INDEX_OUT_OF_BOUND; + OEMCryptoResult result = GetNextAvailable(&gKeyTable, &next); + if (result == OEMCrypto_SUCCESS) { + MoveToUsed(&gKeyTable, next); + gKeyTable.entries[next].key.size = (KeySize)size; + gKeyTable.entries[next].key.key_type = key_type; + memcpy(gKeyTable.entries[next].key.aes_key, key_bytes, size); + } + *index = next; + return result; +} + +OEMCryptoResult K2_RemoveKey(uint32_t index) { + if (!K2_IsIndexValid(index) || !gKeyTable.entries[index].is_used) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + MoveToFree(&gKeyTable, index); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.h b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.h new file mode 100644 index 0000000..8d285d5 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/layer2_crypto_key_table.h @@ -0,0 +1,87 @@ +/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#ifndef OEMCRYPTO_TA_LAYER2_CRYPTO_KEY_TABLE_H_ +#define OEMCRYPTO_TA_LAYER2_CRYPTO_KEY_TABLE_H_ + +#include +#include +#include + +#include "OEMCryptoCENCCommon.h" +#include "oemcrypto_key_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * This header file provides functions of the AES key table which simulates a + * hardware-backed key table with a limited number of key slots. They should be + * only called by the TEST implementation of Crypto and Key Management layer 2. + ******************************************************************************/ + +/** + * Initializes the layer 2 key table. + */ +OEMCryptoResult K2_InitializeKeyTable(void); + +/** + * Checks if |index| is a valid key slot in the key table. Returns true if it + * is. Otherwise returns false. + */ +bool K2_IsIndexValid(uint32_t index); + +/** + * Checks if the key in key slot |index| is valid. Returns true if it is. + * Otherwise returns false. + */ +bool K2_IsKeyValid(uint32_t index); + +/** + * Adds |size| bytes of |key_bytes| as a key entry to the key table, and sets + * |index| to the allocated key slot. + * Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, or + * if |size| is 0. Returns OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if the key + * table runs out of key slots and key eviction fails. + * Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and + * OEMCrypto_SUCCESS otherwise. + * Caller retains ownership of all pointers. + */ +OEMCryptoResult K2_AddKey(const uint8_t* key_bytes, size_t size, + SymmetricKeyType key_type, uint32_t* index); + +/** + * Removes key in key slot |index|. + * Returns OEMCrypto_ERROR_INVALID_CONTEXT if |index| is not valid, and + * OEMCrypto_SUCCESS otherwise. + */ +OEMCryptoResult K2_RemoveKey(uint32_t index); + +/** + * Returns the AES key bytes from key slot |index|. |index| must be valid. + */ +uint8_t* K2_GetKey(uint32_t index); + +/** + * Returns the AES key size from key slot |index|. |index| must be valid. + */ +KeySize K2_GetKeySize(uint32_t index); + +/** + * Returns the AES key type from key slot |index|. |index| must be valid. + */ +SymmetricKeyType K2_GetKeyType(uint32_t index); + +/** + * Sets the key eviction handler. The handler takes a key slot to be evicted and + * returns OEMCryptoResult. + */ +void K2_SetEvictionCallback(OEMCryptoResult (*callback)(uint32_t)); + +#ifdef __cplusplus +} +#endif + +#endif /* OEMCRYPTO_TA_LAYER2_CRYPTO_KEY_TABLE_H_ */ diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk new file mode 100644 index 0000000..ea56b37 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk @@ -0,0 +1,59 @@ +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This file lists out the files that implement the WTPI and transport layer for +# the OPTEE port. This includes a few reference files from `wtpi_reference`, as +# well as stubs from `wtpi_useless` that must be replaced for a production +# build. +# +# This is not necessary for other ports. This only exists to consoldiate all of +# the OPTEE-specific code in one place for use in sub.mk + +wtpi_impl_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl +wtpi_stub_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_useless +wtpi_ref_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_reference +tos_impl_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common +opk_config_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common + +wtpi_impl_sources += \ + $(wtpi_ref_dir)/wtpi_config.c \ + $(wtpi_ref_dir)/wtpi_crypto_and_key_management_layer1_openssl.c \ + $(wtpi_ref_dir)/wtpi_crypto_asymmetric.c \ + $(wtpi_ref_dir)/wtpi_decrypt_sample.c \ + $(wtpi_impl_dir)/wtpi_init_and_clock_ipc.c \ + $(wtpi_ref_dir)/wtpi_provisioning_4.c \ + $(wtpi_impl_dir)/wtpi_provisioning_4_linux.c \ + $(wtpi_ref_dir)/wtpi_abort.c \ + $(wtpi_ref_dir)/wtpi_device_key.c \ + $(wtpi_ref_dir)/crypto_util.c \ + $(wtpi_ref_dir)/device_key_util.c \ + $(wtpi_ref_dir)/rsa_util.c \ + $(wtpi_ref_dir)/ecc_util.c \ + $(wtpi_ref_dir)/cose_util.c \ + $(wtpi_ref_dir)/wtpi_logging.c \ + $(wtpi_ref_dir)/wtpi_root_of_trust_layer1.c \ + $(wtpi_ref_dir)/renewal_util.c \ + $(wtpi_ref_dir)/wtpi_clock_and_gn_layer1.c \ + $(wtpi_ref_dir)/wtpi_crc32.c \ + $(wtpi_ref_dir)/wtpi_crypto_wrap_asymmetric.c \ + $(wtpi_ref_dir)/wtpi_idle.c \ + $(wtpi_ref_dir)/wtpi_device_renewal_layer1.c \ + $(wtpi_ref_dir)/wtpi_device_renewal_layer2.c \ + $(wtpi_stub_dir)/wtpi_device_key_access.c \ + $(wtpi_stub_dir)/wtpi_persistent_storage.c \ + $(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c \ + $(wtpi_stub_dir)/wtpi_secure_buffer_access.c \ + $(wtpi_stub_dir)/wtpi_fused.c \ + $(tos_impl_dir)/tos_secure_buffers.c \ + $(tos_impl_dir)/tos_transport.cpp \ + +wtpi_impl_includes += \ + $(wtpi_impl_dir) \ + $(wtpi_ref_dir) \ + $(wtpi_ref_dir)/../wtpi \ + $(oemcrypto_dir)/include \ + $(opk_config_dir) \ + + diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer2_hw.c b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer2_hw.c new file mode 100644 index 0000000..0f950ad --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer2_hw.c @@ -0,0 +1,478 @@ +/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_crypto_and_key_management_interface_layer2.h" + +#include +#include +#include + +#include "crypto_util.h" +#include "layer2_crypto_key_table.h" +#include "oemcrypto_compiler_attributes.h" +#include "oemcrypto_key_types.h" +#include "oemcrypto_math.h" +#include "oemcrypto_overflow.h" +#include "openssl/aes.h" +#include "openssl/bio.h" +#include "openssl/cmac.h" +#include "openssl/evp.h" +#include "openssl/hmac.h" +#include "openssl/rand.h" +#include "openssl/rsa.h" +#include "openssl/x509.h" +#include "rsa_util.h" +#include "wtpi_abort_interface.h" +#include "wtpi_device_key_access_interface.h" + +/****************************************************************************** + * This is a test implementation of Crypto and Key Management layer 2, + * which simulates a hardware-backed cryptography. The keys stored in a + * pre-allocated table with limited number of slots. OpenSSL is used here as a + * replacement of the hardware crypto. + ******************************************************************************/ + +typedef struct wtpi_k2_symmetric_key_handle { + uint32_t index; +} wtpi_k2_symmetric_key_handle; + +bool WTPI_K2_IsKeyHandleValid(WTPI_K2_SymmetricKey_Handle key_handle) { + return ((key_handle != NULL) && K2_IsKeyValid(key_handle->index)); +} + +OEMCryptoResult WTPI_K2_GetKeyType(WTPI_K2_SymmetricKey_Handle key_handle, + SymmetricKeyType* type) { + if (key_handle == NULL || type == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *type = K2_GetKeyType(key_handle->index); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_K2_GetKeySize(WTPI_K2_SymmetricKey_Handle key_handle, + KeySize* size) { + if (key_handle == NULL || size == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *size = K2_GetKeySize(key_handle->index); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_K2_InitializeKeyManagement(void) { + return K2_InitializeKeyTable(); +} + +OEMCryptoResult WTPI_K2_TerminateKeyManagement(void) { + return OEMCrypto_SUCCESS; +} + +/****************************************************************************** + The following implement the key mapping interface. +*******************************************************************************/ + +bool KM_IsLayer2KeyIndexValid(uint32_t k2_index) { + return K2_IsIndexValid(k2_index); +} + +OEMCryptoResult KM_GetLayer2KeyIndex(WTPI_K2_SymmetricKey_Handle key_handle, + uint32_t* k2_index) { + if (key_handle == NULL || k2_index == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *k2_index = key_handle->index; + return OEMCrypto_SUCCESS; +} + +void KM_SetLayer2KeyEvictionCallback(OEMCryptoResult (*callback)(uint32_t)) { + K2_SetEvictionCallback(callback); +} + +/****************************************************************************** + The following implement the layer 2 crypto interface. +*******************************************************************************/ + +OEMCryptoResult WTPI_C2_AESCBCEncrypt(WTPI_K2_SymmetricKey_Handle key_handle, + const uint8_t* in, size_t in_length, + const uint8_t* iv, uint8_t* out) { + if (key_handle == NULL || in == NULL || in_length == 0 || + in_length % AES_BLOCK_SIZE != 0 || iv == NULL || out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + if (!OPKI_AESCBCEncrypt(in, in_length, iv, key, (size_t)key_size, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +static OEMCryptoResult DeriveKeyWithCMACToKeyHandle( + const uint8_t* key, KeySize key_size, uint8_t counter, + const uint8_t* context, size_t context_length, + SymmetricKeyType out_key_type, KeySize out_key_size, + WTPI_K2_SymmetricKey_Handle* out_key_handle) { + if ((out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256) || + context == NULL || context_length <= 0 || out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t buffer[KEY_SIZE_256]; + if (!OPKI_DeriveKeyWithCMAC(key, key_size, counter, context, context_length, + out_key_size, buffer)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return WTPI_K2_CreateKeyHandle(buffer, out_key_size, out_key_type, + out_key_handle); +} + +OEMCryptoResult WTPI_C2_AESCBCDecrypt(WTPI_K2_SymmetricKey_Handle key_handle, + size_t key_length, const uint8_t* in, + size_t in_length, const uint8_t* iv, + uint8_t* out) { + if (key_handle == NULL || + (key_length != KEY_SIZE_128 && key_length != KEY_SIZE_256) || + in == NULL || in_length == 0 || in_length % AES_BLOCK_SIZE != 0 || + iv == NULL || out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (key_length > K2_GetKeySize(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + if (!OPKI_AESCBCDecrypt(in, in_length, iv, key, key_length, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_AESCTRDecrypt(WTPI_K2_SymmetricKey_Handle key_handle, + const uint8_t* in, size_t in_length, + const uint8_t* iv, size_t block_offset, + uint8_t* out) { + if (key_handle == NULL || in == NULL || in_length == 0 || + block_offset >= AES_BLOCK_SIZE || iv == NULL || out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + if (!OPKI_AESCTRDecrypt(in, in_length, iv, key, (size_t)key_size, + block_offset, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_HMAC_SHA1(WTPI_K2_SymmetricKey_Handle key_handle, + const uint8_t* message, size_t message_length, + uint8_t* out) { + if (key_handle == NULL || message == NULL || message_length == 0 || + out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + if (!OPKI_HMAC_SHA1(message, message_length, key, (size_t)key_size, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_SHA256(const uint8_t* message, size_t message_length, + uint8_t* out) { + if (message == NULL || message_length == 0 || out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!SHA256(message, message_length, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_HMAC_SHA256(WTPI_K2_SymmetricKey_Handle key_handle, + const uint8_t* message, + size_t message_length, uint8_t* out) { + if (key_handle == NULL || message == NULL || message_length == 0 || + out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!K2_IsKeyValid(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + if (!OPKI_HMAC_SHA256(message, message_length, key, (size_t)key_size, out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_HMAC_SHA256_Verify( + WTPI_K2_SymmetricKey_Handle key_handle, const uint8_t* message, + size_t message_length, const uint8_t* signature) { + if (signature == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t computed_signature[SHA256_DIGEST_LENGTH]; + OEMCryptoResult result = WTPI_C2_HMAC_SHA256( + key_handle, message, message_length, computed_signature); + if (result != OEMCrypto_SUCCESS) return result; + if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_C2_RandomBytes(uint8_t* out, size_t size) { + if (out == NULL || size == 0) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (RAND_bytes(out, (int)size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + return OEMCrypto_SUCCESS; +} + +/****************************************************************************** + The following implement the layer 2 key management interface. +*******************************************************************************/ + +OEMCryptoResult WTPI_K2_CreateKeyHandle( + const uint8_t* serialized_bytes, size_t size, SymmetricKeyType key_type, + WTPI_K2_SymmetricKey_Handle* out_key_handle) { + if (serialized_bytes == NULL || size == 0 || out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (size != KEY_SIZE_128 && size != KEY_SIZE_256) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + WTPI_K2_SymmetricKey_Handle handle = + malloc(sizeof(wtpi_k2_symmetric_key_handle)); + if (handle == NULL) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint32_t index; + OEMCryptoResult result = K2_AddKey(serialized_bytes, size, key_type, &index); + if (result != OEMCrypto_SUCCESS) { + free(handle); + return result; + } + handle->index = index; + *out_key_handle = handle; + return result; +} + +OEMCryptoResult WTPI_K2_DeriveDeviceKeyIntoHandle( + uint32_t context, SymmetricKeyType out_key_type, + WTPI_K2_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) { + if (out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + const uint8_t* device_key = WTPI_GetDeviceKey(); + KeySize device_key_size = WTPI_GetDeviceKeySize(); + WTPI_K2_SymmetricKey_Handle temp_key_handle = NULL; + OEMCryptoResult result = WTPI_K2_CreateKeyHandle( + device_key, device_key_size, DERIVING_KEY, &temp_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + // Prepare full context for key derivation + // Server and client MAC keys must derive to the same key. + const SymmetricKeyType type_temp = + out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type; + // Cast the type into 32 bits so it is the same size as the gap left for it in + // full_context. This will be a no-op on most architectures. + const uint32_t type_32 = (uint32_t)type_temp; + // Build a full context that is unique to this starting context / key type + // combination. We start with a context template with blanks at the beginning + // and fill the blanks with the starting context and key type. + uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', + 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; + const size_t context_length = sizeof(full_context); + memcpy(full_context, &context, 4); + memcpy(full_context + 4, &type_32, 4); + const uint8_t counter = 1; + result = WTPI_K2_DeriveKeyFromKeyHandle( + temp_key_handle, counter, (const uint8_t*)full_context, context_length, + out_key_type, out_key_size, out_key_handle); + WTPI_K2_FreeKeyHandle(temp_key_handle); + return result; +} + +OEMCryptoResult WTPI_K2_AESDecryptAndCreateKeyHandle( + WTPI_K2_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key, + size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type, + WTPI_K2_SymmetricKey_Handle* out_key_handle) { + if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 || + iv == NULL || out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_key_length != KEY_SIZE_128 && enc_key_length != KEY_SIZE_256) { + /* Generic crypto allows both key sizes. */ + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(decrypt_key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t raw_key[KEY_SIZE_256]; + KeySize key_size; + OEMCryptoResult result = WTPI_K2_GetKeySize(decrypt_key_handle, &key_size); + if (result != OEMCrypto_SUCCESS) return result; + result = WTPI_C2_AESCBCDecrypt(decrypt_key_handle, (size_t)key_size, enc_key, + enc_key_length, iv, raw_key); + if (result != OEMCrypto_SUCCESS) return result; + WTPI_K2_SymmetricKey_Handle handle = NULL; + result = WTPI_K2_CreateKeyHandle(raw_key, enc_key_length, key_type, &handle); + if (result != OEMCrypto_SUCCESS) return result; + *out_key_handle = handle; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_K2_AESDecryptAndCreateKeyHandleForMacKeys( + WTPI_K2_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys, + size_t enc_mac_keys_length, const uint8_t* iv, + WTPI_K2_SymmetricKey_Handle* out_mac_key_server, + WTPI_K2_SymmetricKey_Handle* out_mac_key_client) { + if (decrypt_key_handle == NULL || enc_mac_keys == NULL || + enc_mac_keys_length == 0 || iv == NULL || out_mac_key_server == NULL || + out_mac_key_client == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_mac_keys_length != 2 * MAC_KEY_SIZE) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(decrypt_key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t raw_mac_keys[2 * MAC_KEY_SIZE]; + KeySize key_size; + OEMCryptoResult result = WTPI_K2_GetKeySize(decrypt_key_handle, &key_size); + if (result != OEMCrypto_SUCCESS) return result; + result = + WTPI_C2_AESCBCDecrypt(decrypt_key_handle, (size_t)key_size, enc_mac_keys, + enc_mac_keys_length, iv, raw_mac_keys); + if (result != OEMCrypto_SUCCESS) return result; + WTPI_K2_SymmetricKey_Handle server_handle = NULL; + result = WTPI_K2_CreateKeyHandle(raw_mac_keys, MAC_KEY_SIZE, MAC_KEY_SERVER, + &server_handle); + if (result != OEMCrypto_SUCCESS) return result; + WTPI_K2_SymmetricKey_Handle client_handle = NULL; + result = WTPI_K2_CreateKeyHandle(raw_mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE, + MAC_KEY_CLIENT, &client_handle); + if (result != OEMCrypto_SUCCESS) { + WTPI_K2_FreeKeyHandle(server_handle); + return result; + } + *out_mac_key_server = server_handle; + *out_mac_key_client = client_handle; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_K2_DeriveKeyFromKeyHandle( + WTPI_K2_SymmetricKey_Handle key_handle, uint8_t counter, + const uint8_t* context, size_t context_length, + SymmetricKeyType out_key_type, KeySize out_key_size, + WTPI_K2_SymmetricKey_Handle* out_key_handle) { + if (key_handle == NULL || context == NULL || context_length == 0 || + out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + if (K2_GetKeyType(key_handle->index) != DERIVING_KEY) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return DeriveKeyWithCMACToKeyHandle(key, key_size, counter, context, + context_length, out_key_type, + out_key_size, out_key_handle); +} + +OEMCryptoResult WTPI_K2_WrapKey(uint32_t context, + WTPI_K2_SymmetricKey_Handle key_handle, + SymmetricKeyType key_type, uint8_t* wrapped_key, + size_t wrapped_key_length) { + if (key_handle == NULL || wrapped_key == NULL || wrapped_key_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (key_type != K2_GetKeyType(key_handle->index)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + KeySize key_size = K2_GetKeySize(key_handle->index); + if (wrapped_key_length != key_size) { + /* The caller should give us the correct buffer size. */ + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + uint8_t* key = K2_GetKey(key_handle->index); + + /* TODO(b/158766099): encrypt the data instead of memcpy. */ + memcpy(wrapped_key, key, key_size); + + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_K2_UnwrapIntoKeyHandle( + uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length, + SymmetricKeyType key_type, WTPI_K2_SymmetricKey_Handle* out_key_handle) { + if (wrapped_key == NULL || wrapped_key_length == 0 || + out_key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (wrapped_key_length != KEY_SIZE_128 && + wrapped_key_length != KEY_SIZE_256) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + /* TODO(b/158766099): decrypt the key data before creating key handle. */ + + return WTPI_K2_CreateKeyHandle(wrapped_key, wrapped_key_length, key_type, + out_key_handle); +} + +OEMCryptoResult WTPI_K2_EncryptKeyHandle( + WTPI_K2_SymmetricKey_Handle key_handle, + WTPI_K2_SymmetricKey_Handle encrypt_key_handle, const uint8_t* iv, + uint8_t* out) { + if (key_handle == NULL || encrypt_key_handle == NULL || iv == NULL || + out == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + uint8_t* key = K2_GetKey(key_handle->index); + KeySize key_size = K2_GetKeySize(key_handle->index); + + return WTPI_C2_AESCBCEncrypt(encrypt_key_handle, key, key_size, iv, out); +} + +OEMCryptoResult WTPI_K2_FreeKeyHandle(WTPI_K2_SymmetricKey_Handle key_handle) { + if (key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (!WTPI_K2_IsKeyHandleValid(key_handle)) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + OEMCryptoResult result = K2_RemoveKey(key_handle->index); + free(key_handle); + return result; +} diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_device_renewal_layer2_test.c b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_device_renewal_layer2_test.c new file mode 100644 index 0000000..95ad421 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_device_renewal_layer2_test.c @@ -0,0 +1,30 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_device_renewal_interface_layer2.h" + +#include + +#include "oemcrypto_check_macros.h" +#include "oemcrypto_key_types.h" + +OEMCryptoResult WTPI_GetRenewalInfo(uint32_t old_system_id, + uint32_t* new_system_id, + uint8_t* renewal_key, + size_t renewal_key_length) { + ABORT_IF(old_system_id != 0x1ee8, "Unexpected old system ID"); + ABORT_IF_NULL(new_system_id); + ABORT_IF_NULL(renewal_key); + ABORT_IF(renewal_key_length != KEY_SIZE_128, "Unexpected renewal key size"); + + // The following magic values map to the renewal twin of the test keybox and + // were exchanged with the provisioning team out-of-band. + *new_system_id = 25421; + static const uint8_t kRenewalKey[KEY_SIZE_128] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + }; + memcpy(renewal_key, kRenewalKey, KEY_SIZE_128); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_init_and_clock_ipc.c b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_init_and_clock_ipc.c new file mode 100644 index 0000000..fc02f65 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_init_and_clock_ipc.c @@ -0,0 +1,30 @@ +/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_clock_interface_layer2.h" + +#include + +#include "OEMCryptoCENC.h" +#include "wtpi_initialize_terminate_interface.h" +#include "wtpi_logging_interface.h" + +// This implementation is used when we do not have access to a clock that can do +// fake sleeps. + +OEMCryptoResult WTPI_GetSecureTimer(uint64_t* time_in_s) { + if (!time_in_s) return OEMCrypto_ERROR_INVALID_CONTEXT; + *time_in_s = time(0); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_Initialize(void) { + LOGD("WTPI_Initialize."); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_Terminate(void) { + LOGD("WTPI_Terminate."); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_provisioning_4_linux.c b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_provisioning_4_linux.c new file mode 100644 index 0000000..16fd624 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_provisioning_4_linux.c @@ -0,0 +1,91 @@ +/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_config_interface.h" + +#include "wtpi_provisioning_4_interface.h" + +#include "cose_util.h" +#include "dice/cbor_writer.h" +#include "malloc.h" + +#define DEVICE_INFO_MAX_LENGTH 256 + +size_t WTPI_MaxDeviceInfoSize(void) { return DEVICE_INFO_MAX_LENGTH; } + +OEMCryptoResult WTPI_GetDeviceInformation(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + size_t max_device_info_size = WTPI_MaxDeviceInfoSize(); + if (out == NULL || *out_length < max_device_info_size) { + *out_length = max_device_info_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *out_length = max_device_info_size; + + // DeviceInfo = { + // "manufacturer" : tstr, + // "model" : tstr, + // "fused": 1 / 0, ; 1 if secure boot is enforced. 0 otherwise. + // } + const char* kMakeLabel = "manufacturer"; + const char* kModelLabel = "model"; + const char* kFusedLabel = "fused"; + struct CborOut cbor_out; + CborOutInit(out, *out_length, &cbor_out); + CborWriteMap(/*num_pairs=*/3, &cbor_out); + CborWriteTstr(kMakeLabel, &cbor_out); + CborWriteTstr("google", &cbor_out); + CborWriteTstr(kModelLabel, &cbor_out); + CborWriteTstr("www", &cbor_out); + CborWriteTstr(kFusedLabel, &cbor_out); + CborWriteInt(0, &cbor_out); + if (CborOutOverflowed(&cbor_out)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *out_length = CborOutSize(&cbor_out); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetSignedCsrPayload(const uint8_t* challenge, + size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_length) { + if (challenge == NULL || challenge_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encoded_device_info == NULL || encoded_device_info_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + size_t max_cose_sign1_size; + OEMCryptoResult result = WTPI_GetMaxBccKeyCoseSign1Size(&max_cose_sign1_size); + if (result != OEMCrypto_SUCCESS) return result; + if (signed_csr_payload == NULL || + *signed_csr_payload_length < max_cose_sign1_size) { + *signed_csr_payload_length = max_cose_sign1_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *signed_csr_payload_length = max_cose_sign1_size; + + /* Generate Csr payload to be signed. */ + uint8_t* csr_payload = (uint8_t*)malloc(max_cose_sign1_size); + if (csr_payload == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + size_t csr_payload_length = max_cose_sign1_size; + result = GenerateCsrPayload(challenge, challenge_length, encoded_device_info, + encoded_device_info_length, csr_payload, + &csr_payload_length); + if (result != OEMCrypto_SUCCESS) { + free(csr_payload); + return result; + } + + /* Sign Csr payload. */ + result = WTPI_BccKeyCoseSign1(csr_payload, csr_payload_length, + signed_csr_payload, signed_csr_payload_length); + free(csr_payload); + return result; +} 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 new file mode 100644 index 0000000..92be777 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp @@ -0,0 +1,85 @@ +# Copyright 2021 Google LLC.All Rights Reserved.This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. + +{ + 'variables': { + 'oemcrypto_ta_dir' : '<(DEPTH)/oemcrypto/opk/oemcrypto_ta', + 'odk_dir' : '<(DEPTH)/oemcrypto/odk', + # TODO(b/207176111): add test scripts to cover both reference crypto impl + 'reference_crypto_impl%': 'software', + 'test_renewal%': 0, + # Path to wtpi implementations that pass tests but are unsuitable for + # production use. + 'wtpi_stub_dir': '<(oemcrypto_ta_dir)/wtpi_useless', + 'use_provisioning_40%': 0, + }, + 'target_defaults': { + 'toolsets' : [ 'target' ], + 'type': 'static_library', + 'include_dirs': [ + '<(opk_config_dir)', + '<(oemcrypto_ta_dir)/wtpi_reference', + '<(DEPTH)/third_party/open-dice/include', + '<(DEPTH)/util/include', + 'test-only', + '.', + '<(odk_dir)/include', + ], + 'sources': [ + 'wtpi_provisioning_4_linux.c', + 'test-only/wtpi_persistent_storage.c', + 'test-only/file_store_interface.c', + 'test-only/wtpi_device_key_access.c', + '<(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c', + '<(wtpi_stub_dir)/wtpi_secure_buffer_access.c', + '<(wtpi_stub_dir)/wtpi_fused.c', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_config.c', + ], + 'conditions': [ + ['reference_crypto_impl=="hardware"', { + 'sources': [ + 'layer2_crypto_key_table.c', + 'wtpi_crypto_and_key_management_layer2_hw.c', + ], + }], + ['test_renewal', { + 'sources': [ + 'wtpi_device_renewal_layer2_test.c', + ], + }], + ['use_provisioning_40', { + 'defines': [ + 'OPK_CONFIG_PROVISIONING_METHOD=OEMCrypto_BootCertificateChain', + ], + }], + ], + 'dependencies': [ + '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_linux_tee', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_abort', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_clock', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_crypto', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_idle', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_logging', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_renewal', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_root_of_trust', + ], + }, + 'targets': [{ + # This target is used when we have the serialization IPC in the loop. In + # that case, we cannot use a fake clock. + 'target_name': 'oemcrypto_ta_test_impl_ipc', + 'sources': [ + 'wtpi_init_and_clock_ipc.c', + ], + }, + { + # This target is used when we do not have the serialization IPC in the + # loop. In that case, we can use a fake clock, but we also don't have the + # serialization level telling us what the wall clock. + 'target_name': 'oemcrypto_ta_test_impl_no_ipc', + 'sources': [ + 'test-only/wtpi_init_and_clock_no_ipc.cpp', + ], + }], +} diff --git a/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/Makefile b/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/Makefile new file mode 100644 index 0000000..8cf9ede --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/Makefile @@ -0,0 +1,64 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This Makefile is not intended to be invoked on its own. It is possible +# though. Be sure to set the following variables. +# - CDM_DIR: path to top of CDM repo + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project) + +# Define this for tee-sources.mk, which uses it as a prefix for source file +# locations +OPK_REPO_TOP := +# tee-sources.mk provides opk_base_ta_sources and opk_base_ta_includes +include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk +include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk + +# Definitions for wtpi_impl sources.mk +wtpi_impl_dir := $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl + +# Provides wtpi_impl_sources and wtpi_impl_includes +include $(CDM_DIR)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk + +srcs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/clock.cpp \ + $(tos_impl_dir)/tos_shared_memory.cpp \ + $(opk_base_ta_sources) \ + $(wtpi_impl_sources) \ + $(boringssl_sources) \ + $(dice_sources) \ + +incs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common \ + $(OPK_REPO_TOP)/util/include \ + $(opk_base_ta_includes) \ + $(wtpi_impl_includes) \ + $(boringssl_includes) \ + $(dice_includes) \ + +cflags += \ + -DWV_POSIX_RESOURCE_ID=\"$(project)\" \ + -DOPK_CONFIG_SOC_VENDOR_NAME=$(SOC_VENDOR) \ + -DOPK_CONFIG_SOC_MODEL_NAME=$(SOC_MODEL) \ + -DOPK_CONFIG_TEE_OS_NAME=$(TEE_OS) \ + -DOPK_CONFIG_TEE_OS_VERSION=$(TEE_VERSION) \ + -DOPK_CONFIG_DEVICE_FORM_FACTOR=$(DEVICE_FORM_FACTOR) \ + -DOPK_CONFIG_IMPLEMENTER_NAME=$(IMPLEMENTER) \ + -DOPK_CONFIG_PROVISIONING_METHOD=$(PROVISIONING_METHOD) \ + -D_DEFAULT_SOURCE + + # -D_DEBUG + +ldflags = \ + -lrt -lpthread \ + +include ../../rules.mk + diff --git a/oemcrypto/opk/ports/linux/ta/tee_simulator/README.md b/oemcrypto/opk/ports/linux/ta/tee_simulator/README.md new file mode 100644 index 0000000..eda3342 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/tee_simulator/README.md @@ -0,0 +1,23 @@ +# Linux-IPC-Test port of the OPK + +The linux-ipc-test port of OPK is a sample implementation of the OPK transport and +shared memory interfaces that runs in two separate linux processes to verify the +serialization and deserialization functionality. The TEE side is implemented in +a tee_simulator linux process, and the REE side implements the OEMCrypto API. The +TEE side contains the OEMCrypto TA. The REE side runs the oemcrypto test suite. + +``` +File structure: + ./oemcrypto + build file for liboemcrypto.so + ./serialization_adapter + implementation of os_interfaces/tos_transport_interface.h + implementation of os_interfaces/tos_shared_memory_interface.h + implementation of os_interfaces/opk_secure_buffer_interface.h + ./serialization_adapter/test + test for the shared memory implementation + ./tee_simulator + TEE main loop, calls implementation of tee_dispatcher.h +``` + + diff --git a/oemcrypto/opk/ports/linux/ta/wtpi_test_ta/Makefile b/oemcrypto/opk/ports/linux/ta/wtpi_test_ta/Makefile new file mode 100644 index 0000000..e3241b9 --- /dev/null +++ b/oemcrypto/opk/ports/linux/ta/wtpi_test_ta/Makefile @@ -0,0 +1,72 @@ +# +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# + +# This Makefile is not intended to be invoked on its own. It is possible +# though. Be sure to set the following variables. +# - CROSS_COMPILE: prefix of compiler, eg arm-linux-gnueabihf- +# - CDM_DIR: path to top of CDM repo + +# Place outputs in $CDM_DIR/out/linux// +project := $(shell basename $(CURDIR)) +srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR)) +builddir := $(srcdir)/out/linux/$(project)/ +output = $(project) + +# Define this for tee-sources.mk, which uses it as a prefix for source file +# locations +OPK_REPO_TOP := +# tee-sources.mk provides opk_base_ta_sources and opk_base_ta_includes +include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk +include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk + +# Definitions for wtpi_impl sources.mk +wtpi_impl_dir := $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl + +# Provides wtpi_impl_sources and wtpi_impl_includes +include $(CDM_DIR)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk + +# $(info $(boringssl_sources)) + +# srcs-y, global-incdirs-y, and libnames are used by the OP-TEE TA dev kit +# build system +srcs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/clock.cpp \ + $(tos_impl_dir)/tos_shared_memory.cpp \ + $(oemcrypto_ta_dir)/oemcrypto_asymmetric_key_table.c \ + $(oemcrypto_ta_dir)/oemcrypto_object_table.c \ + $(oemcrypto_ta_dir)/oemcrypto_key.c \ + $(opk_base_wtpi_ta_sources) \ + $(wtpi_impl_sources) \ + $(boringssl_sources) \ + $(dice_sources) \ + +incs += \ + $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common \ + $(OPK_REPO_TOP)/util/include \ + $(opk_base_wtpi_ta_includes) \ + $(wtpi_impl_includes) \ + $(oemcrypto_ta_includes) \ + $(boringssl_includes) \ + $(dice_includes) \ + + +cflags += \ + -DWV_POSIX_RESOURCE_ID=\"$(project)\" \ + -DOPK_CONFIG_SOC_VENDOR_NAME=$(SOC_VENDOR) \ + -DOPK_CONFIG_SOC_MODEL_NAME=$(SOC_MODEL) \ + -DOPK_CONFIG_TEE_OS_NAME=$(TEE_OS) \ + -DOPK_CONFIG_TEE_OS_VERSION=$(TEE_VERSION) \ + -DOPK_CONFIG_DEVICE_FORM_FACTOR=$(DEVICE_FORM_FACTOR) \ + -DOPK_CONFIG_IMPLEMENTER_NAME=$(IMPLEMENTER) \ + -DOPK_CONFIG_PROVISIONING_METHOD=$(PROVISIONING_METHOD) \ + -D_DEFAULT_SOURCE + +ldflags = \ + -lrt -lpthread \ + +include ../../rules.mk + diff --git a/oemcrypto/opk/ports/linux/wtpi_tee_simulator.gyp b/oemcrypto/opk/ports/linux/wtpi_tee_simulator.gyp new file mode 100644 index 0000000..f376eaa --- /dev/null +++ b/oemcrypto/opk/ports/linux/wtpi_tee_simulator.gyp @@ -0,0 +1,60 @@ +# +# Builds tee_simulator executable, which includes Linux-based +# implementation of transport and shared memory. +# +# Dependencies: +# OPK serialization library for TEE [ 'tee.gyp:opk_tee' ] +# Implementation of porting layer API ['wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc'] +{ + 'includes' : { + '../../oemcrypto_ta/wtpi_test/settings.gypi', + }, + 'variables': { + 'wtpi_impl' : '<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc', + 'platform_specific_dir%': '<(DEPTH)/linux/src', + 'tee_simulator_dir' : '<(oemcrypto_dir)/opk/ports/linux/ta/common', + 'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/common', + + 'privacy_crypto_impl%': 'boringssl', + 'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto', + 'boringssl_libssl_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:ssl', + 'gtest_dependency%': '<(DEPTH)/third_party/googletest.gyp:gtest', + 'gmock_dependency%': '<(DEPTH)/third_party/googletest.gyp:gmock', + 'oemcrypto_dir%': '<(DEPTH)/oemcrypto', + 'util_dir%': '<(DEPTH)/util', + }, + 'target_defaults': { + 'include_dirs' : [ + 'ta/common/wtpi_impl', + '<(serialization_adapter_dir)', + '<(serialization_dir)/tee/include', + '<(tee_dir)', + '<(util_dir)/include', + ], + }, + 'targets' : [ + { + 'target_name': 'tee_simulator', + 'type': 'executable', + 'sources': [ + '<(serialization_adapter_dir)/tos_logging.cpp', + '<(serialization_adapter_dir)/tos_secure_buffers.c', + '<(serialization_adapter_dir)/tos_shared_memory.cpp', + '<(serialization_adapter_dir)/tos_transport.cpp', + '<(tee_simulator_dir)/clock.cpp', + '<(tee_simulator_dir)/tee_simulator.cpp', + '<(platform_specific_dir)/file_store.cpp', + '<(platform_specific_dir)/log.cpp', + '<(util_dir)/src/platform.cpp', + '<(util_dir)/src/rw_lock.cpp', + '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', + ], + 'dependencies': [ + '<(tee_dir)/tee.gyp:opk_tee_wtpi_test', + '<(wtpi_impl)', + ], + 'libraries': ['-lrt', '-lpthread', '-ldl'], + }, + ] +} diff --git a/oemcrypto/opk/ports/optee/Makefile b/oemcrypto/opk/ports/optee/Makefile index 7285563..ae19b81 100644 --- a/oemcrypto/opk/ports/optee/Makefile +++ b/oemcrypto/opk/ports/optee/Makefile @@ -27,10 +27,25 @@ endif # Default is QEMU OPTEE_PLATFORM ?= qemu CFG_TEE_TA_MALLOC_DEBUG:=y +IS_ARM:=1 + +# For build information. Replace with your own values in each build as needed. +SOC_VENDOR := test +SOC_MODEL := test +TEE_OS := OP-TEE +TEE_VERSION := 3.18 +DEVICE_FORM_FACTOR := test # overridden later by OP-TEE $(PLATFORM) var. Feel free to replace with own values +IMPLEMENTER := your-name-here # Default toolchain dir from the optee repositories OPTEE_TOOLCHAIN_DIR ?= $(OPTEE_DIR)/toolchains +# need to undefine this to avoid looking for . Including libc in the +# compiler include paths leads to a huge amount of redundant-decl compiler +# warnings +CPPFLAGS := \ + -U__linux__ \ + ifeq ($(OPTEE_PLATFORM),qemu) PLATFORM ?= vexpress-qemu_virt ARCH := 32 @@ -38,9 +53,15 @@ TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch32 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32 CROSS_COMPILE := arm-linux-gnueabihf- -WTPI_BUILD_INFO := OPTEE_QEMU -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/arm-none-linux-gnueabihf/libc/usr/include \ + +else ifeq ($(OPTEE_PLATFORM),qemuv8) +PLATFORM ?= vexpress-qemu_armv8a +ARCH := 64 +TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec +OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch64 +TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm64 +CROSS_COMPILE := aarch64-linux-gnu- +SOC_MODEL := qemuv8 else ifeq ($(OPTEE_PLATFORM),stm32mp1) PLATFORM ?= stm32mp1-157A-DK1 @@ -49,9 +70,6 @@ TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch32 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32 CROSS_COMPILE := arm-linux-gnueabihf- -WTPI_BUILD_INFO := OPTEE_STM32MP1 -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/arm-none-linux-gnueabihf/libc/usr/include \ else ifeq ($(OPTEE_PLATFORM),nxpimx8m) PLATFORM ?= imx-mx8mqevk @@ -60,15 +78,13 @@ TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch64 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm64 CROSS_COMPILE := aarch64-linux-gnu- -WTPI_BUILD_INFO := OPTEE_IMX8 -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/aarch64-none-linux-gnu/libc/usr/include \ else $(error Unknown OPTEE_PLATFORM "$(OPTEE_PLATFORM)" Check makefile for possible options.) endif PATH := $(OPTEE_TOOLCHAIN)/bin:$(PATH) +DEVICE_FORM_FACTOR := $(PLATFORM) .PHONY: all all: host ta diff --git a/oemcrypto/opk/ports/optee/README.md b/oemcrypto/opk/ports/optee/README.md index 064b3ba..77b2817 100644 --- a/oemcrypto/opk/ports/optee/README.md +++ b/oemcrypto/opk/ports/optee/README.md @@ -1,39 +1,48 @@ This is a port of the OEMCrypto Trusted App for OP-TEE using the OPK. -### Quick build steps +### Quick start -1. Make sure you have an OPTEE repo setup somewhere. Set that path to the - environment variable OPTEE_DIR. If the GCC toolchain is separate from the one - included in $OPTEE_DIR/toolchains, set that path to OPTEE_TOOLCHAIN_DIR. -2. Set up the third_party directory. The makefiles for unit tests reference - googletest and boringssl, and expect them to be under a top level directory - called "third_party": - ``` - # From the top level of the repo - $ mkdir third_party - $ git clone https://github.com/google/googletest.git googletest - $ mkdir boringssl && cd boringssl - $ mkdir kit && cd kit - $ git clone https://boringssl.googlesource.com/boringssl src && cd src +This will build for 32-bit QEMU, which is the default OP-TEE repo setup. For +other targets, be sure to set up the OP-TEE repos with the corresponding +manifest (eg to build OPK against an NXP chip target, use the correct NXP +manifest when cloning and building OP-TEE). - # Commits after this change some filenames, which is incompatible with - # current OPK makefiles - $ git checkout 1e15682f1a4bb64c48b84884976a2b5c4201e878 - $ cd ../ - $ python ./src/util/generate_build_files.py gyp - ``` -2. From the top level of this repo (CDM), run `make -j32 -C +1. Download and build OP-TEE following their online documentation. Set that + destination to the environment variable OPTEE_DIR. If the GCC toolchain is + separate from the one included in $OPTEE_DIR/toolchains, set that path to + OPTEE_TOOLCHAIN_DIR. +2. Set up the third_party directory with the required dependencies. All of these + dependencies are for unit tests. Run `oemcrypto/opk/setup.sh` to download all + of the required libraries to `$CDM_DIR/third_party`. +3. From the top level of this repo (CDM), run `make -j32 -C ./oemcrypto/opk/ports/optee host ta` +4. Run on QEMU +``` +export QEMU=$OPTEE_DIR/qemu/build/arm-softmmu/qemu-system-arm && \ +export GTEST_FILTER="-*Reboot*" && \ +ln -sf $OPTEE_DIR/out-br/images/rootfs.cpio.gz $OPTEE_DIR/out/bin/ && \ +cd $OPTEE_DIR/out/bin && \ +python3 $CDM_DIR/oemcrypto/opk/ports/optee/scripts/qemu-check.py --qemu=$QEMU --test_cmd="./wtpi_unittests --gtest_filter=$GTEST_FILTER" +``` The resulting artifacts will run on QEMU, but due to performance constraints not all tests will pass there. For best results the executables should be built for NXP and run on the iMX8 dev kit (see Makefile for the variables that specify the -NXP target). Currently the following tests are expected to fail, with fixes -expected in future updates: +NXP target). -WTPI unit tests that do not pass -- CryptoTest.GenerateRandomCertificateKeyPairSuccess -- CryptoTest.WTPI_DeviceKeyCoseSign1Success +By default, the Makefile under `oemcrypto/opk/ports/optee/` will build against +the QEMU 32-bit platform target. Other platforms are supported, and can be built +using the OPTEE_PLATFORM build variable, eg `make -j32 -C +./oemcrypto/opk/ports/optee all OPTEE_PLATFORM=qemuv8`. For a full list of +supported platforms, see the Makefile. Note that the OPTEE_PLATFORM values do +not match OP-TEE's values for the PLATFORM build variable. + +**For 64-bit targets**: If you are using provisioning 4 +(OPK_CONFIG_PROVISIONING_METHOD is set to OEMCrypto_BootCertificateChain), +WPTI_GenerateRandomCertificateKeyPair() will fail due to insufficient memory. +We suggest increasing MPI_MEMPOOL_SIZE from 12k to 14k in optee_os/lib/libutee/ +tee_api_arith_mpi.c to avoid this. This does not seem to be a problem on 32- +bit targets. ### Background @@ -65,15 +74,17 @@ And the following components on the TEE side: ### OEMCrypto TA The Makefile in `ta/oemcrypto_ta` will build a Trusted App that implements -OEMCrypto functions and can be installed on OP-TEE. Using the above list as -a reference, the TEE-specific components include +OEMCrypto functions and can be installed on OP-TEE. To do this, it calls the +makefiles included with the OP-TEE distribution and provides lists of source +files to compile. Using the above list as a reference, the resulting +TEE-specific components include - A trusted application entry point for messages: TA_InvokeCommandEntryPoint() - TOS function implementations: `host/common/tos` -- Deserialization layer: included as `libopk_tee` from the serialization - directory -- OEMCrypto function implementations: included as `liboemcrypto_ta` from the - oemcrypto_ta directory +- Deserialization layer: included as `serialization_common_sources` from + tee-sources.mk +- OEMCrypto function implementations: included as `oemcrypto_ta_sources` from + tee-sources.mk - WTPI function implementations: `ta/common/wtpi_impl`. These are specific to GlobalPlatform. @@ -107,7 +118,7 @@ WTPI functions, while the serialization layer for the OEMCrypto app targets OEMCrypto functions. Unlike the OEMCrypto TA, the WTPI test host app does not link against -liboemcrypto.so +liboemcrypto.so. This is because there are no OEMCrypto functions to serialize. ### Build and run on QEMU @@ -173,3 +184,19 @@ cd /mnt/host/oemcrypto/test # run OEMCrypto unit tests ./oemcrypto_unittests ``` + +### Scripts + +The `scripts` folder contains various utility scripts to help build, run, and +test OP-TEE builds. Many of them rely on the environment variable $OPTEE_DIR, +which is the location of the OP-TEE codebase. + +- `qemu-check.py`: Launch QEMU, execute commands, and extract test results. + Tuned to OP-TEE running gtest executables such as wtpi_unittests. Uses pexpect + to communicate with QEMU and parse results +- `push.sh`: Intended to be run from the compilation environment in the CDM + repo. Simply copies the build outputs from the CDM repo into $OPTEE_DIR, along + with `install_ta.sh`. Works well with 9p virtfs-enabled QEMU. +- `install_ta.sh`: Intended to be run on the target platform in the host + environment. Installs the OEMCrypto TA and WTPI Test TA into OP-TEE using + xtest diff --git a/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c b/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c index dbe8064..8aa30a6 100644 --- a/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c +++ b/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c @@ -15,8 +15,7 @@ void TOS_SecureBuffer_Pack(ODK_Message* message, const OEMCrypto_DestBufferDesc* obj) { /* secure memory - pack handle, length, offset */ - OPK_Pack_uint64_t(message, - (const uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Pack_size_t(message, (const size_t*)&obj->buffer.secure.secure_buffer); OPK_Pack_size_t(message, &obj->buffer.secure.secure_buffer_length); OPK_Pack_size_t(message, &obj->buffer.secure.offset); } @@ -24,7 +23,7 @@ void TOS_SecureBuffer_Pack(ODK_Message* message, void TOS_SecureBuffer_Unpack(ODK_Message* message, OEMCrypto_DestBufferDesc* obj) { /* secure memory - unpack handle, length, offset */ - OPK_Unpack_uint64_t(message, (uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Unpack_size_t(message, (size_t*)&obj->buffer.secure.secure_buffer); OPK_Unpack_size_t(message, &obj->buffer.secure.secure_buffer_length); OPK_Unpack_size_t(message, &obj->buffer.secure.offset); } diff --git a/oemcrypto/opk/ports/optee/host/liboemcrypto/Makefile b/oemcrypto/opk/ports/optee/host/liboemcrypto/Makefile index 0b3bf90..aaa56ba 100644 --- a/oemcrypto/opk/ports/optee/host/liboemcrypto/Makefile +++ b/oemcrypto/opk/ports/optee/host/liboemcrypto/Makefile @@ -36,5 +36,11 @@ global-incs += \ ldflags = -lpthread -lteec -L$(TEEC_EXPORT) -shared +# Example to add custom REE-side hook to OEMCrypto_Initialize() before calling +# into TA +# cflags = \ + # -DOPK_PRE_HOOK_OEMCRYPTO_INITIALIZE \ + # -DOPK_HOOK_AND_USE_TA_OEMCRYPTO_INITIALIZE \ + include ../rules.mk diff --git a/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile b/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile index 378782d..4dca131 100644 --- a/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile +++ b/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile @@ -42,5 +42,13 @@ ldflags = \ cppflags += \ -DOPENSSL_NO_ASM \ -Wnon-virtual-dtor \ + -DCOSE_C_USE_OPENSSL \ + -include 'cstdlib' \ + '-DEVP_aes_128_ccm()=EVP_aes_128_gcm()' \ + '-DEVP_aes_256_ccm()=EVP_aes_256_gcm()' \ + '-DEVP_aes_192_ccm()=EVP_aes_192_gcm()' \ + '-DEVP_CTRL_CCM_SET_L=0x14' \ + '-DEVP_CTRL_CCM_GET_TAG=EVP_CTRL_GCM_GET_TAG' \ + '-DEVP_CTRL_CCM_SET_TAG=EVP_CTRL_GCM_SET_TAG' \ include ../rules.mk diff --git a/oemcrypto/opk/ports/optee/install_ta.sh b/oemcrypto/opk/ports/optee/scripts/install_ta.sh similarity index 89% rename from oemcrypto/opk/ports/optee/install_ta.sh rename to oemcrypto/opk/ports/optee/scripts/install_ta.sh index 44fa009..3feac90 100755 --- a/oemcrypto/opk/ports/optee/install_ta.sh +++ b/oemcrypto/opk/ports/optee/scripts/install_ta.sh @@ -5,7 +5,7 @@ OEMCRYPTO_TA=a92d116c-ce27-4917-b30c-4a416e2d9351.ta if test -f $OEMCRYPTO_TA; then echo "Installing OEMCrypto TA" - cp $OEMCRYPTO_TA /lib/optee_armtz && rm $OEMCRYPTO_TA + cp $OEMCRYPTO_TA /lib/optee_armtz xtest --install-ta /lib/optee_armtz/$OEMCRYPTO_TA else if test -f /lib/optee_armtz/$OEMCRYPTO_TA; then @@ -18,7 +18,7 @@ fi WTPI_TEST_TA=b0f42504-01ec-11ec-9a03-0242ac130003.ta if test -f $WTPI_TEST_TA; then echo "Installing WTPI Test TA" - cp $WTPI_TEST_TA /lib/optee_armtz && rm $WTPI_TEST_TA + cp $WTPI_TEST_TA /lib/optee_armtz xtest --install-ta /lib/optee_armtz/$WTPI_TEST_TA else if test -f /lib/optee_armtz/$WTPI_TEST_TA; then @@ -41,6 +41,6 @@ su tee -c "tee-supplicant -d /dev/teepriv0" & # run as "source" to get this to actually propagate to the environment # eg. `. ./install_ta.sh` instead of just `./install_ta.sh` -export LD_LIBRARY_PATH=/mnt/host/oemcrypto/test +export LD_LIBRARY_PATH=$(pwd) export TOS_LOG_LEVEL=4 diff --git a/oemcrypto/opk/ports/optee/push.sh b/oemcrypto/opk/ports/optee/scripts/push.sh similarity index 100% rename from oemcrypto/opk/ports/optee/push.sh rename to oemcrypto/opk/ports/optee/scripts/push.sh diff --git a/oemcrypto/opk/ports/optee/scripts/qemu-check.py b/oemcrypto/opk/ports/optee/scripts/qemu-check.py new file mode 100644 index 0000000..b366664 --- /dev/null +++ b/oemcrypto/opk/ports/optee/scripts/qemu-check.py @@ -0,0 +1,97 @@ +# This script starts QEMU, loads and boots Linux/OP-TEE, then runs +# a googletest exe in the guest. The return code is 0 for success, >0 for +# error. +# +# Makes some assumptions about the environment, namely the location of the +# virtfs directory (/mnt/host/oemcrypto/test) and the steps required to install +# and run the tests +# +# Must be run from $OPTEE_DIR/out/bin so that QEMU can locate the required +# bootloader binaries +# +# The following env variables are expected +# OPTEE_DIR: location of the OPTEE repo root +# +# Example use: +# +# QEMU=$OPTEE_DIR/qemu/build/arm-softmmu/qemu-system-arm +# GTEST_FILTER="-*Reboot*" +# ln -sf $OPTEE_DIR/out-br/images/rootfs.cpio.gz $OPTEE_DIR/out/bin/ +# cd $OPTEE_DIR/out/bin && \ +# python3 $CDM_DIR/oemcrypto/opk/ports/optee/scripts/qemu-check.py --qemu=$QEMU --test_cmd="./wtpi_unittests --gtest_filter=$GTEST_FILTER" +# + +from absl import app +from absl import flags +import os +import sys +import subprocess +import pexpect + +# Required +_QEMU = flags.DEFINE_string('qemu', None, 'Path to QEMU executable.') +_TEST_CMD = flags.DEFINE_string('test_cmd', None, 'Command to run once QEMU is booted and TAs are installed.') + +# Optional +_QEMU_BIOS = flags.DEFINE_string('qemu_bios', os.environ['OPTEE_DIR'] + '/out/bin/bl1.bin', 'Binary for QEMU to run.') +_QEMU_SMP = flags.DEFINE_integer('qemu_smp', 2, 'Number of cores for QEMU.') +_QEMU_GIC = flags.DEFINE_integer('qemu_gic', 2, 'General Interrupt Controller version for QEMU.') +_QEMU_MEM = flags.DEFINE_integer('qemu_mem', 1057, 'QEMU virtual memory size.') +_QUIET = flags.DEFINE_boolean('quiet', False, 'Disable TEE console output.', short_name='q') + +def main(argv): + + # To get QEMU to print TEE output to the same screen as the REE output, log to + # a file and print the tail of that file to stdout. Unfortunately cannot + # easily do this from another pexpect context, so we cannot filter/expect the + # TEE output + tee_serial_out = "null" + if _QUIET.value == False: + tee_serial_out = "file:serial1.log" + os.system('> serial1.log') + + spawn_cmd = '' + if 'aarch64' in _QEMU.value: + spawn_cmd = _QEMU.value + '-nographic -serial mon:stdio -serial ' + tee_serial_out + ' -smp ' + str(_QEMU_SMP.value) + ' -machine virt,secure=on,gic-version=' + str(_QEMU_GIC.value) + ' -cpu cortex-a57 -d unimp -semihosting-config enble=on,target=native -m ' + str(_QEMU_MEM.value) + ' -bios ' + _QEMU_BIOS.value + ' -initrd rootfs.cpio.gz -kernel Image -no-acpi -append "console=ttyAMA0,38400 keep_bootcon root=/dev/vda2" -fsdev local,id=fsdev0,path=' + os.environ['OPTEE_DIR'] + ',security_model=none -device virtio-9p-device,fsdev=fsdev0,mount_tag=host' + else: + spawn_cmd = _QEMU.value + ' -nographic -monitor none -machine virt -machine secure=on -cpu cortex-a15 -smp ' + str(_QEMU_SMP.value) + ' -d unimp -semihosting-config enable=on,target=native -m ' + str(_QEMU_MEM.value) + ' -serial stdio -serial ' + tee_serial_out + ' -bios ' + _QEMU_BIOS.value + ' -fsdev local,id=fsdev0,path=' + os.environ['OPTEE_DIR'] + ',security_model=none -device virtio-9p-device,fsdev=fsdev0,mount_tag=host' + + child = pexpect.spawn(spawn_cmd, encoding='utf-8', timeout=1800) + + p = None + if _QUIET.value == False: + p =subprocess.Popen(['tail', '-f', 'serial1.log']) + + child.logfile = sys.stdout + i = child.expect(['Kernel panic', 'ogin:']) + if i==0: + print("Kernel panic!") + child.terminate() + if _QUIET.value == False: + p.kill() + return 1 + + child.sendline('root') + child.expect('# ') + child.sendline('cd /mnt/host/oemcrypto/test') + child.expect('# ') + child.sendline('. ./install_ta.sh') + child.expect('# ') + child.sendline(_TEST_CMD.value) + + i = child.expect(['^.*su tee -c "tee-supplicant -d /dev/teepriv0"','([^ ]+) FAILED TEST', 'rcu_sched detected stalls', '^.*not found' ]) + if i>0: # Only the 0th element ("su tee etc") is a success case + child.terminate() + if _QUIET.value == False: + p.kill() + return 1 + + child.terminate() + if _QUIET.value == False: + p.kill() + return 0 + +if __name__ == '__main__': + flags.mark_flag_as_required('qemu') + flags.mark_flag_as_required('test_cmd') + app.run(main) diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/asymmetric_key.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/asymmetric_key.h new file mode 100644 index 0000000..c2bcb87 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/asymmetric_key.h @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef _WTPI_OPTEE_ASYMMETRIC_KEY_H_ +#define _WTPI_OPTEE_ASYMMETRIC_KEY_H_ + +#include +#include "wtpi_crypto_asymmetric_interface.h" + +#define ECC_KEY_MAX_BITS 521 +#define ECC_KEY_MAX_BYTES ((ECC_KEY_MAX_BITS + 7) / 8 + 1) +#define PKCS8_2048BIT_RSA_KEY_MAX_SIZE 1300 + +typedef struct tee_asymmetric_key_handle { + TEE_ObjectHandle key_handle; + uint32_t max_signature_size; + uint32_t ecc_curve_type; // only used for ECC operations + TEE_ObjectHandle ecdh_key; // used for ECDH, distinguish between default + // key_handle ECDSA operations +} tee_asymmetric_key_handle; + +OEMCryptoResult Helper_ECCSign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length, + bool der_encode); +#endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_common.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_common.h new file mode 100644 index 0000000..926b486 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_common.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef _WTPI_CRYPTO_COMMON_H_ +#define _WTPI_CRYPTO_COMMON_H_ + +#include "wtpi_crypto_and_key_management_interface_layer1.h" + +typedef struct wtpi_k1_symmetric_key_handle { + uint8_t* key; + uint32_t key_size; // TODO: change to KeySize type + SymmetricKeyType key_type; + TEE_OperationHandle op_cbc; + TEE_OperationHandle op_ecb; // Used for CTR and CBC. We don't know which will + // be used up front, so pre-allocate both for + // CONTENT_KEY types +} wtpi_k1_symmetric_key_handle; + +OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key, + const uint8_t* input, + uint8_t* output); +#endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/opk_config.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/opk_config.h new file mode 100644 index 0000000..e8e0e5a --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/opk_config.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef _OPK_CONFIG_H_ +#define _OPK_CONFIG_H_ + +#ifndef MAX_NUMBER_OF_SESSIONS +# define MAX_NUMBER_OF_SESSIONS 20 +#endif + +#ifndef MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS +# define MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS 10 +#endif + +#ifndef MAX_NUMBER_OF_KEYS +# define MAX_NUMBER_OF_KEYS 100 +#endif + +#ifndef CONTENT_KEYS_PER_SESSION +# define CONTENT_KEYS_PER_SESSION 10 +#endif + +#ifndef ENTITLEMENT_KEYS_PER_SESSION +# define ENTITLEMENT_KEYS_PER_SESSION 10 +#endif + +// Use defaults from wtpi_reference for the rest +#include "config/default.h" + +#endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk index 2f8336c..c50d86c 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk @@ -24,21 +24,38 @@ ifndef optee_inc_dir $(error wtpi_impl/sources.mk included without setting optee_inc_dir) endif +dice_dir ?= $(OPK_REPO_TOP)/third_party/open-dice +dice_sources += \ + $(dice_dir)/src/cbor_reader.c \ + $(dice_dir)/src/cbor_writer.c \ + $(dice_dir)/src/clear_memory.c \ + $(dice_dir)/src/utils.c \ + +dice_includes += \ + $(dice_dir)/include \ + $(dice_dir)/include/dice/config/boringssl_ed25519 \ + wtpi_impl_sources += \ $(wtpi_impl_dir)/util/ta_log.c \ $(wtpi_impl_dir)/util/der_parse.c \ + $(wtpi_impl_dir)/util/odk_endian.c \ + $(wtpi_ref_dir)/cose_util.c \ $(wtpi_impl_dir)/wtpi_abort.c \ $(wtpi_impl_dir)/wtpi_clock_layer2.c \ - $(wtpi_impl_dir)/wtpi_config.c \ + $(wtpi_ref_dir)/wtpi_config.c \ + $(wtpi_impl_dir)/wtpi_cbor_deviceinfo.c \ $(wtpi_impl_dir)/wtpi_crypto_and_key_management_layer1.c \ $(wtpi_impl_dir)/wtpi_crypto_asymmetric.c \ $(wtpi_impl_dir)/wtpi_decrypt_sample.c \ $(wtpi_impl_dir)/wtpi_initialize_terminate_interface.c \ $(wtpi_impl_dir)/wtpi_logging.c \ $(wtpi_impl_dir)/wtpi_persistent_storage_layer2.c \ + $(wtpi_impl_dir)/wtpi_provisioning_4.c \ $(wtpi_impl_dir)/wtpi_root_of_trust_layer1.c \ $(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c \ $(wtpi_stub_dir)/wtpi_secure_buffer_access.c \ + $(wtpi_stub_dir)/wtpi_device_key_access.c \ + $(wtpi_stub_dir)/wtpi_fused.c \ $(wtpi_ref_dir)/renewal_util.c \ $(wtpi_ref_dir)/wtpi_clock_and_gn_layer1.c \ $(wtpi_ref_dir)/wtpi_crc32.c \ @@ -48,6 +65,7 @@ wtpi_impl_sources += \ $(wtpi_ref_dir)/wtpi_device_renewal_layer1.c \ $(wtpi_ref_dir)/wtpi_device_renewal_layer2.c \ $(tos_impl_dir)/optee_secure_buffers.c \ + $(dice_sources) \ wtpi_impl_includes += \ $(wtpi_impl_dir) \ @@ -57,6 +75,7 @@ wtpi_impl_includes += \ $(optee_inc_dir) \ $(optee_inc_dir)/mbedtls \ $(oemcrypto_dir)/include \ + $(dice_includes) \ wtpi_impl_libs += \ mbedtls diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c index 6e82f04..c484c54 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c @@ -12,6 +12,7 @@ #include "ecp.h" #include "pk.h" #include "rsa.h" +#include "sha256.h" // Helper for the mbedtls_asn1_write_* functions. Assumes the existence of // a variable named `ret` with type `int`. @@ -160,33 +161,37 @@ static OEMCryptoResult Helper_EncodeRSAKey( int (*mbedtls_write_fn)(mbedtls_pk_context* ctx, unsigned char* buf, size_t size)) { // import RSA data as raw values into mbedtls_rsa_context - mbedtls_rsa_context rsa_ctx; - mbedtls_rsa_init(&rsa_ctx, MBEDTLS_RSA_PKCS_V15, 0); - + mbedtls_pk_context pk_ctx; + mbedtls_pk_init(&pk_ctx); int result = - mbedtls_rsa_import_raw(&rsa_ctx, key->modulus, key->modulus_len, NULL, 0, - NULL, 0, key->private_exp, key->private_exp_len, - key->public_exp, key->public_exp_len); + mbedtls_pk_setup(&pk_ctx, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (result != 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + mbedtls_rsa_init(mbedtls_pk_rsa(pk_ctx), MBEDTLS_RSA_PKCS_V15, 0); + + result = mbedtls_rsa_import_raw(mbedtls_pk_rsa(pk_ctx), key->modulus, + key->modulus_len, NULL, 0, NULL, 0, + key->private_exp, key->private_exp_len, + key->public_exp, key->public_exp_len); if (result < 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } // calculate remaining RSA parameters (P, Q) - result = mbedtls_rsa_complete(&rsa_ctx); + result = mbedtls_rsa_complete(mbedtls_pk_rsa(pk_ctx)); if (result < 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // assign RSA data to generic mbedtls_pk_context type - mbedtls_pk_context pk_ctx; - const mbedtls_pk_info_t* info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); - mbedtls_pk_setup(&pk_ctx, info); - pk_ctx.pk_ctx = &rsa_ctx; - // write RSA data in DER encoding to output size_t original_output_length = *output_length; int bytes_written = mbedtls_write_fn(&pk_ctx, output, *output_length); if (bytes_written <= 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } *output_length = bytes_written; @@ -196,6 +201,7 @@ static OEMCryptoResult Helper_EncodeRSAKey( TEE_MemMove(output, output + original_output_length - *output_length, *output_length); + mbedtls_pk_free(&pk_ctx); return OEMCrypto_SUCCESS; } @@ -217,6 +223,7 @@ OEMCryptoResult EncodeRSAPublicKey(const pkcs1_rsa* key, uint8_t* output, if (key == NULL || key->modulus == NULL || key->public_exp == NULL || key->modulus_len == 0 || key->public_exp_len == 0 || output == NULL || output_length == NULL) { + EMSG("Failing because of something null or 0"); return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -248,6 +255,30 @@ static uint32_t GlobalPlatformCurveId(mbedtls_ecp_group_id id) { return TEE_CRYPTO_ELEMENT_NONE; } +static mbedtls_ecp_group_id MbedTlsCurveId(uint32_t id) { + switch (id) { + case TEE_ECC_CURVE_NIST_P192: + return MBEDTLS_ECP_DP_SECP192R1; + + case TEE_ECC_CURVE_NIST_P224: + return MBEDTLS_ECP_DP_SECP224R1; + + case TEE_ECC_CURVE_NIST_P256: + return MBEDTLS_ECP_DP_SECP256R1; + + case TEE_ECC_CURVE_NIST_P384: + return MBEDTLS_ECP_DP_SECP384R1; + + case TEE_ECC_CURVE_NIST_P521: + return MBEDTLS_ECP_DP_SECP521R1; + + default: + return MBEDTLS_ECP_DP_NONE; + } + + return MBEDTLS_ECP_DP_NONE; +} + static size_t CurveNumBits(mbedtls_ecp_group_id id) { switch (id) { case MBEDTLS_ECP_DP_SECP192R1: @@ -319,6 +350,19 @@ static size_t ECCSize(size_t num_bits) { return len; } +// If src size is smaller than desired size, reallocate src and front pad with +// 0s. Set src_size to desired size if successful. +static void zero_pad_and_realloc(uint8_t** src, size_t* src_size, + size_t desired_size) { + if (*src_size >= desired_size) return; + uint8_t* const temp = TEE_Malloc(desired_size, 0); + const size_t difference = desired_size - *src_size; + TEE_MemMove(temp + difference, *src, *src_size); + TEE_Free(*src); + *src = temp; + *src_size = desired_size; +} + OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, size_t input_length, rfc5915_eckey* output) { @@ -336,6 +380,7 @@ OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, output->ecc_curve_type = GlobalPlatformCurveId(ec_ctx->grp.id); output->ecc_curve_bits = CurveNumBits(ec_ctx->grp.id); output->max_signature_size = ECCSize(output->ecc_curve_bits); + const size_t ecc_curve_bytes = (output->ecc_curve_bits + 7) / 8; if ((res = extract_mbedtls_mpi_param(&(ec_ctx->d), &output->private_val, &output->private_val_len)) != @@ -349,6 +394,12 @@ OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, &output->public_y_len)) != OEMCrypto_SUCCESS) goto cleanup; + zero_pad_and_realloc(&output->private_val, &output->private_val_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_x, &output->public_x_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, + ecc_curve_bytes); res = OEMCrypto_SUCCESS; @@ -373,6 +424,7 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, output->ecc_curve_type = GlobalPlatformCurveId(ec_ctx->grp.id); output->ecc_curve_bits = CurveNumBits(ec_ctx->grp.id); output->max_signature_size = ECCSize(output->ecc_curve_bits); + const size_t ecc_curve_bytes = (output->ecc_curve_bits + 7) / 8; if ((res = extract_mbedtls_mpi_param(&(ec_ctx->Q.X), &output->public_x, &output->public_x_len)) != @@ -383,6 +435,11 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, OEMCrypto_SUCCESS) goto cleanup; + zero_pad_and_realloc(&output->public_x, &output->public_x_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, + ecc_curve_bytes); + res = OEMCrypto_SUCCESS; cleanup: @@ -447,3 +504,83 @@ OEMCryptoResult EncodeECDSASignature(const uint8_t* sig, size_t sig_length, return OEMCrypto_SUCCESS; } + +OEMCryptoResult DeriveEccKey(const uint8_t* seed, size_t seed_length, + uint32_t curve_id, rfc5915_eckey* output) { + if (seed == NULL || seed_length == 0 || output == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + OEMCryptoResult res = OEMCrypto_ERROR_UNKNOWN_FAILURE; + + // grp will contain ECC generator point G + mbedtls_ecp_group grp; + mbedtls_ecp_group_init(&grp); + + // privkey will be the hashed seed used to calculate the public key + mbedtls_mpi privkey; + mbedtls_mpi_init(&privkey); + + // pubkey will be the (X,Y) point calculated by multiplying privkey*G + mbedtls_ecp_point pubkey; + mbedtls_ecp_point_init(&pubkey); + + // Hash seed + // Not all OPTEE builds support SHA512. We still want 64 bytes of material in + // case of ECC P384 or P521, so use same SHA256 hash twice + uint8_t hash[64]; + mbedtls_sha256(seed, seed_length, hash, 0); + mbedtls_sha256(seed, seed_length, hash + 32, 0); + + // Copy hashed result into mbedtls mpi struct, treat it as the private key + mbedtls_ecp_group_id id = MbedTlsCurveId(curve_id); + size_t curve_len_bits = CurveNumBits(id); + size_t curve_len = (curve_len_bits + 7) / 8; + int mbedtls_res = mbedtls_mpi_read_binary(&privkey, hash, curve_len); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Use a static generator point G for the provided curve + // mbedtls_ecp_group_load loads a known set of fields for a given curve + mbedtls_res = mbedtls_ecp_group_load(&grp, id); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Multiply private val by G + mbedtls_res = mbedtls_ecp_mul(&grp, &pubkey, &privkey, &(grp.G), NULL, NULL); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Copy results into output struct + output->ecc_curve_type = curve_id; + output->ecc_curve_bits = curve_len_bits; + output->max_signature_size = ECCSize(curve_len_bits); + + if ((res = extract_mbedtls_mpi_param(&privkey, &output->private_val, + &output->private_val_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + if ((res = extract_mbedtls_mpi_param(&(pubkey.X), &output->public_x, + &output->public_x_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + if ((res = extract_mbedtls_mpi_param(&(pubkey.Y), &output->public_y, + &output->public_y_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + zero_pad_and_realloc(&output->private_val, &output->private_val_len, + curve_len); + zero_pad_and_realloc(&output->public_x, &output->public_x_len, curve_len); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, curve_len); + + res = OEMCrypto_SUCCESS; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&pubkey); + mbedtls_mpi_free(&privkey); + return res; +} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h index 1e88856..b79aa19 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h @@ -114,4 +114,15 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, OEMCryptoResult EncodeECDSASignature(const uint8_t* sig, size_t sig_length, uint8_t* output, size_t* output_length); +/* + * Given a buffer of bytes |seed| and a curve type |curve_id|, produce a + * deterministic public and private keypair for ECC operations. + * + * |curve_id| is the GlobalPlatform enum for curve types, eg + * TEE_ECC_CURVE_NIST_P256 + * + */ +OEMCryptoResult DeriveEccKey(const uint8_t* seed, size_t seed_length, + uint32_t curve_id, rfc5915_eckey* output); + #endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/odk_endian.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/odk_endian.c new file mode 100644 index 0000000..343d08e --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/odk_endian.c @@ -0,0 +1,54 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include + +#include "odk_endian.h" + +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 + +// default is little endian unless specified otherwise at build time +#ifndef BYTE_ORDER +# define BYTE_ORDER LITTLE_ENDIAN +#endif + +/* Swap bytes in 16-bit value. */ +#define __bswap_constant_16(x) \ + ((uint16_t)((((x) >> 8) & 0xff) | (((x)&0xff) << 8))) + +/* Swap bytes in 32-bit value. */ +#define __bswap_constant_32(x) \ + ((((x)&0xff000000u) >> 24) | (((x)&0x00ff0000u) >> 8) | \ + (((x)&0x0000ff00u) << 8) | (((x)&0x000000ffu) << 24)) + +/* Swap bytes in 64-bit value. */ +#define __bswap_constant_64(x) \ + ((((x)&0xff00000000000000ull) >> 56) | (((x)&0x00ff000000000000ull) >> 40) | \ + (((x)&0x0000ff0000000000ull) >> 24) | (((x)&0x000000ff00000000ull) >> 8) | \ + (((x)&0x00000000ff000000ull) << 8) | (((x)&0x0000000000ff0000ull) << 24) | \ + (((x)&0x000000000000ff00ull) << 40) | (((x)&0x00000000000000ffull) << 56)) + +#if BYTE_ORDER == LITTLE_ENDIAN +// Little endian +// swap all + +uint32_t oemcrypto_htobe16(uint16_t u16) { return __bswap_constant_16(u16); } +uint32_t oemcrypto_be16toh(uint16_t u16) { return __bswap_constant_16(u16); } +uint32_t oemcrypto_htobe32(uint32_t u32) { return __bswap_constant_32(u32); } +uint32_t oemcrypto_be32toh(uint32_t u32) { return __bswap_constant_32(u32); } +uint64_t oemcrypto_htobe64(uint64_t u64) { return __bswap_constant_64(u64); } +uint64_t oemcrypto_be64toh(uint64_t u64) { return __bswap_constant_64(u64); } + +#elif BYTE_ORDER == BIG_ENDIAN +// Big endian +// keep all + +uint32_t oemcrypto_htobe16(uint16_t u16) { return u16; } +uint32_t oemcrypto_be16toh(uint16_t u16) { return u16; } +uint32_t oemcrypto_htobe32(uint32_t u32) { return u32; } +uint32_t oemcrypto_be32toh(uint32_t u32) { return u32; } +uint64_t oemcrypto_htobe64(uint64_t u64) { return u64; } +uint64_t oemcrypto_be64toh(uint64_t u64) { return u64; } +#endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_cbor_deviceinfo.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_cbor_deviceinfo.c new file mode 100644 index 0000000..03db811 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_cbor_deviceinfo.c @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#include "wtpi_provisioning_4_interface.h" + +#define DEVICE_INFO_MAX_LENGTH 256 + +size_t WTPI_MaxDeviceInfoSize(void) { return DEVICE_INFO_MAX_LENGTH; } + +OEMCryptoResult WTPI_GetDeviceInformation(uint8_t* device_info, + size_t* device_info_length) { + (void)device_info; + (void)device_info_length; + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult WTPI_GetSignedCsrPayload(const uint8_t* challenge, + size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_length) { + (void)challenge; + (void)challenge_length; + (void)encoded_device_info; + (void)encoded_device_info_length; + (void)signed_csr_payload; + (void)signed_csr_payload_length; + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c deleted file mode 100644 index 838d83b..0000000 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine - * License Agreement. - */ - -#include "wtpi_config_interface.h" - -OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) { - return OEMCrypto_Level1; -} - -OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { - return OEMCrypto_Keybox; -} - -uint32_t WTPI_GetResourceRatingTier(void) { return 1; } - -OPK_FeatureStatus WTPI_IsTAAntiRollbackEnabled(void) { - return OPK_FEATURE_NOT_SUPPORTED; -} - -bool WTPI_IsProductionReady(void) { return false; } - -OEMCrypto_WatermarkingSupport WTPI_GetWatermarkingSupport(void) { - return OEMCrypto_WatermarkingNotSupported; -} - -OEMCrypto_DTCP2_Capability WTPI_GetDTCP2Capability(void) { - return OEMCrypto_NO_DTCP2; -} - -OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) { - if (srm_version == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - *srm_version = 0; - return OEMCrypto_SUCCESS; -} - -bool WTPI_IsAntiRollbackHWPresent(void) { return false; } - -OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field) { - (void)cgms_field; - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -bool WTPI_IsCGMS_AActive(void) { return false; } - -bool WTPI_SupportsCGMS_A(void) { return false; } - -bool WTPI_HasAnalogDisplay(void) { return false; } - -bool WTPI_IsAnalogDisplayActive(void) { return false; } - -bool WTPI_CanDisableAnalogDisplay(void) { return false; } - -bool WTPI_DisableAnalogDisplay(void) { return false; } - -size_t WTPI_MaxBufferSizeForDecrypt(void) { return 0; } - -size_t WTPI_MaxOutputSizeForDecrypt(void) { return 0; } - -bool WTPI_IsClosedPlatform(void) { return false; } - -OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { - return HDCP_NO_DIGITAL_OUTPUT; -} - -OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) { - return HDCP_NO_DIGITAL_OUTPUT; -} - -size_t WTPI_MaxBufferSizeForGenericCrypto(void) { return 0; } - -size_t WTPI_MaxSampleSize(void) { return 0; } - -// GlobalPlatform spec says "256, 512, 768, 1024, 1536 and 2048 bit keys SHALL -// be supported." -uint32_t WTPI_SupportedCertificates(void) { - return OEMCrypto_Supports_RSA_2048bit; -} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h deleted file mode 100644 index 7750c38..0000000 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine - * License Agreement. - */ - -#ifndef _WTPI_CONFIG_MACROS_H_ -#define _WTPI_CONFIG_MACROS_H_ - -/** - * Following should not be more than UINT32_MAX - 1. - */ -#define MAX_NUMBER_OF_SESSIONS 20 -#define MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS 10 -#define MAX_NUMBER_OF_KEYS 100 -#define CONTENT_KEYS_PER_SESSION 10 -#define ENTITLEMENT_KEYS_PER_SESSION 10 -/** This is the number of usage entries in the header. */ -#define MAX_NUMBER_OF_USAGE_ENTRIES 300 -/** The number of active entries that may be loaded simultaneously. */ -#define MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES 10 -/** The number of active DRM keys that may be loaded simultaneously. */ -#define MAX_NUMBER_OF_ASYMMETRIC_KEYS 8 -/** This is the number of key slots in the layer 2 symmetric key table. */ -#define MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES 8 - -/** - * The crypto hardware may be asked to wrap a key so that it is less vulnerable - * to attack. This is the size of a wrapped mac key. - */ -#define WRAPPED_MAC_KEY_SIZE 32 - -/** - * The extra size (in bytes) that is required by WTPI_EncryptAndSign. If - * supporting backwards-compatibility with multiple versions of WrappedData, - * this value should be as big as the version with the largest amount of - * overhead. */ -#define ENCRYPT_AND_SIGN_EXTRA 68 -#define MAX_SYMMETRIC_KEY_SIZE 32 -#define MAX_WRAPPED_SYMMETRIC_KEY_SIZE MAX_SYMMETRIC_KEY_SIZE -#define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \ - (PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA) - -#endif // _WTPI_CONFIG_MACROS_H_ diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c index 5ea7bd9..2e5d8b8 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c @@ -7,6 +7,7 @@ #include #include #include +#include "crypto_common.h" #include "der_parse.h" #include "malloc.h" #include "oemcrypto_check_macros.h" @@ -18,44 +19,9 @@ #include "wtpi_abort_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_device_key_access_interface.h" #include "wtpi_device_key_interface.h" - -/* - * - * TODO(b/206651517): Replace raw key data with pre-allocated - * TEE_OperationHandle and TEE_ObjectHandle. - * - * GlobalPlatform requires that a TEE_ObjectHandle is constructed with - * a specific operation in mind. For example, if we want to construct a key - * handle for a SHA1 operation, we specify SHA1 when we assign the key to the - * handle. Similarly for SHA256, we specify SHA256 during TEE_ObjectHandle - * construction. - * - * Unfortunately, the current SymmetricKeyType enum does not have that level of - * granularity. We use MAC_KEY_CLIENT for both SHA1 and SHA256 operations, so - * a CreateKeyHandle() request does not have enough information for us to - * guarantee a valid TEE_ObjectHandle result. - * - * To get around this, we re-allocate the TEE_OperationHandle (for the crypto - * operation we want) and TEE_ObjectHandle (for the key associated with that - * crypto operation) for every symmetric key crypto function; we don't know - * enough information to do this until the actual WTPI function is called. At - * the end of the function, we free the op/key handles. - * - * Asymmetric keys still have this problem, but to a lesser degree. The - * AsymmetricKeyType enum does not specify signing vs decrypting, so we don't - * know which operation handle to generate if we're given that enum value. - * Thankfully, those are the only two operations we do, so it's not burdensome - * to pre-allocate both options. The key object is even easier, there's only one - * choice (TEE_TYPE_RSA_KEYPAIR). - * - * TODO: also maybe add key type as a member? good to check compatibility with - * desired operation, eg. don't try to AES encrypt with an HMAC key - */ -typedef struct wtpi_k1_symmetric_key_handle { - uint8_t* key; - uint32_t key_size; // TODO: change to KeySize type -} wtpi_k1_symmetric_key_handle; +#include "wtpi_secure_buffer_access_interface.h" OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key, KeySize* size) { @@ -71,60 +37,31 @@ OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_NULL(output); RETURN_INVALID_CONTEXT_IF_NULL(key); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; - uint32_t algo = TEE_ALG_AES_ECB_NOPAD; - uint32_t mode = TEE_MODE_ENCRYPT; - uint32_t size = key->key_size * 8; - TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); - if (res != TEE_SUCCESS) { - EMSG("TEE_AllocateOperation() failed with result 0x%x", res); - goto err; + TEE_OperationHandle op_handle = key->op_ecb; + if (op_handle == TEE_HANDLE_NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; } - res = TEE_AllocateTransientObject(TEE_TYPE_AES, size, &key_handle); - if (res != TEE_SUCCESS) { - EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); - goto err; - } - TEE_Attribute attr; - TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); - - res = TEE_PopulateTransientObject(key_handle, &attr, 1); - if (res != TEE_SUCCESS) { - EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); - goto err; - } - - res = TEE_SetOperationKey(op_handle, key_handle); - if (res != TEE_SUCCESS) { - EMSG("TEE_SetOperationKey() failed with result 0x%x", res); - goto err; - } - - TEE_CipherInit(op_handle, NULL, 0); - size_t output_len = 128; size_t in_length = AES_BLOCK_SIZE; - res = TEE_CipherUpdate(op_handle, input, in_length, output, &output_len); + TEE_CipherInit(op_handle, NULL, 0); + TEE_Result res = + TEE_CipherUpdate(op_handle, input, in_length, output, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_CipherUpdate() failed with result 0x%x", res); if (output_len != 128) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } - if (op_handle != TEE_HANDLE_NULL) TEE_FreeOperation(op_handle); - if (key_handle != TEE_HANDLE_NULL) TEE_FreeTransientObject(key_handle); return OEMCrypto_SUCCESS; err: - if (op_handle != TEE_HANDLE_NULL) TEE_FreeOperation(op_handle); - if (key_handle != TEE_HANDLE_NULL) TEE_FreeTransientObject(key_handle); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, size_t key_length_to_use, const uint8_t* in, size_t in_length, @@ -133,8 +70,30 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, if (mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + + size_t output_len = in_length; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + + // special case: CreateKey would have allocated a CBC+Decrypt key already for + // the CONTENT_KEY type, so just use it here + if (key->key_type == CONTENT_KEY && mode == TEE_MODE_DECRYPT) { + op_handle = key->op_cbc; + TEE_CipherInit(op_handle, iv, 16); + + TEE_Result res = + TEE_CipherUpdate(op_handle, in, in_length, out, &output_len); + if (res != TEE_SUCCESS) { + EMSG("TEE_CipherUpdate() failed with result 0x%x", res); + if (output_len != in_length) { + EMSG("output_len was changed to %zu", output_len); + } + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; + } + + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; uint32_t algo = TEE_ALG_AES_CBC_NOPAD; uint32_t size = key_length_to_use * 8; TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); @@ -149,7 +108,6 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key_length_to_use); @@ -167,12 +125,11 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, TEE_CipherInit(op_handle, iv, 16); - size_t output_len = in_length; res = TEE_CipherUpdate(op_handle, in, in_length, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_CipherUpdate() failed with result 0x%x", res); if (output_len != in_length) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -225,8 +182,10 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(out); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; + size_t output_len = 32; uint32_t algo = TEE_ALG_HMAC_SHA1; uint32_t mode = TEE_MODE_MAC; uint32_t size = key->key_size * 8; @@ -241,7 +200,6 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); res = TEE_PopulateTransientObject(key_handle, &attr, 1); @@ -259,12 +217,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, TEE_MACInit(op_handle, NULL, 0); TEE_MACUpdate(op_handle, message, message_length); - size_t output_len = 32; res = TEE_MACComputeFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -287,7 +244,10 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, TEE_Result res; - TEE_OperationHandle op_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + size_t chunk_len = 32; + size_t remaining_len = message_length; + size_t output_len = 32; uint32_t algo = TEE_ALG_SHA256; uint32_t mode = TEE_MODE_DIGEST; res = TEE_AllocateOperation(&op_handle, algo, mode, 0); @@ -296,8 +256,6 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, goto err; } - size_t chunk_len = 32; - size_t remaining_len = message_length; for (size_t i = 0; i < message_length; i += chunk_len) { if (remaining_len < chunk_len) { chunk_len = remaining_len; @@ -306,12 +264,11 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, remaining_len -= chunk_len; } - size_t output_len = 32; res = TEE_DigestDoFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_DigestDoFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -334,11 +291,28 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(out); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; +// If the key is too small, pad it until it is at the minimum allowed by +// GlobalPlatform +#define MIN_OPTEE_HMAC_SHA256_SIZE 256 + if (key->key_size * 8 < MIN_OPTEE_HMAC_SHA256_SIZE) { + uint8_t temp[MIN_OPTEE_HMAC_SHA256_SIZE / 8]; + TEE_MemFill(temp, 0, sizeof(temp)); + TEE_MemMove(temp, key->key, key->key_size); + TEE_Free(key->key); + key->key = TEE_Malloc(sizeof(temp), TEE_MALLOC_FILL_ZERO); + TEE_MemMove(key->key, temp, sizeof(temp)); + key->key_size = sizeof(temp); + } +#undef MIN_OPTEE_HMAC_SHA256_SIZE + + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; + size_t output_len = 32; uint32_t algo = TEE_ALG_HMAC_SHA256; uint32_t mode = TEE_MODE_MAC; uint32_t size = key->key_size * 8; + TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); if (res != TEE_SUCCESS) { EMSG("Could not allocate op with result 0x%x, %u, %u, %u", res, algo, mode, @@ -351,7 +325,6 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); res = TEE_PopulateTransientObject(key_handle, &attr, 1); @@ -368,12 +341,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, TEE_MACInit(op_handle, NULL, 0); TEE_MACUpdate(op_handle, message, message_length); - size_t output_len = 32; res = TEE_MACComputeFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -420,14 +392,16 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer(const uint8_t* in, size_t size, return OEMCrypto_ERROR_INVALID_CONTEXT; } - // TODO: secure buffer + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - - uint8_t* const dest = out->buffer.clear_insecure + output_offset; TEE_MemMove(dest, in, size); return OEMCrypto_SUCCESS; @@ -479,10 +453,75 @@ OEMCryptoResult WTPI_K1_CreateKeyHandle( EMSG("Malloc failed, out of memory"); goto err; } + TEE_MemMove(key_space, serialized_bytes, size); sess->key = key_space; - sess->key_size = (uint32_t)size; + sess->key_type = key_type; + + // Special case of CONTENT_KEY type, preallocate key handle and CTR+CBC + // operation handles. Every other operation generates operation handles on the + // fly + if (key_type == CONTENT_KEY) { + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + uint32_t key_size = size * 8; + TEE_Result res = + TEE_AllocateTransientObject(TEE_TYPE_AES, key_size, &key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); + goto err; + } + + TEE_Attribute attr; + TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, serialized_bytes, size); + res = TEE_PopulateTransientObject(key_handle, &attr, 1); + if (res != TEE_SUCCESS) { + EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + goto err; + } + + // CBC + TEE_OperationHandle op_handle_cbc = TEE_HANDLE_NULL; + uint32_t algo = TEE_ALG_AES_CBC_NOPAD; + uint32_t mode = TEE_MODE_DECRYPT; + res = TEE_AllocateOperation(&op_handle_cbc, algo, mode, key_size); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + goto err; + } + res = TEE_SetOperationKey(op_handle_cbc, key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + TEE_FreeOperation(op_handle_cbc); + goto err; + } + + // CTR + TEE_OperationHandle op_handle_ctr = TEE_HANDLE_NULL; + algo = TEE_ALG_AES_ECB_NOPAD; + mode = TEE_MODE_ENCRYPT; + res = TEE_AllocateOperation(&op_handle_ctr, algo, mode, key_size); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + TEE_FreeOperation(op_handle_cbc); + goto err; + } + res = TEE_SetOperationKey(op_handle_ctr, key_handle); + TEE_FreeTransientObject(key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_FreeOperation(op_handle_cbc); + TEE_FreeOperation(op_handle_ctr); + goto err; + } + + sess->op_cbc = op_handle_cbc; + sess->op_ecb = op_handle_ctr; + } *out_key_handle = sess; return OEMCrypto_SUCCESS; @@ -496,14 +535,15 @@ err: OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( uint32_t context, SymmetricKeyType out_key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) { - // TODO (b/201702904): Use a persistent, device-unique key - const uint8_t fake_device_key[KEY_SIZE_128] = { - 0xa2, 0xe5, 0x11, 0x54, 0x12, 0x60, 0xf0, 0xe1, - 0xa8, 0x72, 0xeb, 0x15, 0x48, 0x41, 0xc7, 0x87}; + const uint8_t* device_key = WTPI_GetDeviceKey(); + const KeySize device_key_len = WTPI_GetDeviceKeySize(); + if (device_key == NULL || device_key_len != KEY_SIZE_128) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } WTPI_K1_SymmetricKey_Handle temp_key_handle; OEMCryptoResult result = WTPI_K1_CreateKeyHandle( - fake_device_key, KEY_SIZE_128, DERIVING_KEY, &temp_key_handle); + device_key, KEY_SIZE_128, DERIVING_KEY, &temp_key_handle); if (result != OEMCrypto_SUCCESS) return result; uint8_t full_context[16] = {'.', '.', '.', '.', 'W', 'i', 'd', 'e', @@ -594,8 +634,8 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( return OEMCrypto_ERROR_INVALID_CONTEXT; } - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; uint32_t algo = TEE_ALG_AES_CMAC; uint32_t mode = TEE_MODE_MAC; @@ -644,7 +684,7 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != KEY_SIZE_128) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -662,9 +702,10 @@ err: return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -OEMCryptoResult WTPI_K1_WrapKey(UNUSED uint32_t context, +OEMCryptoResult WTPI_K1_WrapKey(uint32_t context UNUSED, WTPI_K1_SymmetricKey_Handle key, - SymmetricKeyType key_type, uint8_t* wrapped_key, + SymmetricKeyType key_type UNUSED, + uint8_t* wrapped_key, size_t wrapped_key_length) { RETURN_INVALID_CONTEXT_IF_NULL(key); RETURN_INVALID_CONTEXT_IF_NULL(wrapped_key); @@ -682,7 +723,7 @@ OEMCryptoResult WTPI_K1_WrapKey(UNUSED uint32_t context, } OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( - UNUSED uint32_t context, const uint8_t* wrapped_key, + uint32_t context UNUSED, const uint8_t* wrapped_key, size_t wrapped_key_length, SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle) { RETURN_INVALID_CONTEXT_IF_NULL(wrapped_key); @@ -704,8 +745,19 @@ OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) { return OEMCrypto_SUCCESS; } + if (key_handle->op_cbc != TEE_HANDLE_NULL) + TEE_FreeOperation(key_handle->op_cbc); + if (key_handle->op_ecb != TEE_HANDLE_NULL) + TEE_FreeOperation(key_handle->op_ecb); + TEE_Free(key_handle->key); TEE_Free(key_handle); return OEMCrypto_SUCCESS; } + +OEMCryptoResult WTPI_K1_PrepareExternalKeyHandle( + WTPI_K1_SymmetricKey_Handle key_handle UNUSED, uint8_t* out_buffer UNUSED, + size_t* out_buffer_length UNUSED) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c index df6e0f9..4e1fa5b 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c @@ -7,6 +7,7 @@ #include #include #include +#include "asymmetric_key.h" #include "der_parse.h" #include "malloc.h" #include "oemcrypto_check_macros.h" @@ -14,22 +15,12 @@ #include "oemcrypto_key_types.h" #include "oemcrypto_math.h" #include "oemcrypto_overflow.h" +#include "opk_config.h" #include "tos_shared_memory_interface.h" +#include "util/der_parse.h" #include "wtpi_abort_interface.h" -#include "wtpi_config_macros.h" #include "wtpi_crypto_asymmetric_interface.h" - -#define ECC_KEY_MAX_BITS 521 -#define ECC_KEY_MAX_BYTES ((ECC_KEY_MAX_BITS + 7) / 8 + 1) -#define PKCS8_2048BIT_RSA_KEY_MAX_SIZE 1300 - -typedef struct tee_asymmetric_key_handle { - TEE_ObjectHandle key_handle; - uint32_t max_signature_size; - uint32_t ecc_curve_type; // only used for ECC operations - TEE_ObjectHandle ecdh_key; // used for ECDH, distinguish between default - // key_handle ECDSA operations -} tee_asymmetric_key_handle; +#include "wtpi_device_key_access_interface.h" static OEMCryptoResult Helper_CreateRSAKeyHandle( const uint8_t* serialized_bytes, size_t size, @@ -116,6 +107,8 @@ cleanup: static OEMCryptoResult Helper_CreateECCKeyHandle( const uint8_t* serialized_bytes, size_t size, WTPI_AsymmetricKey_Handle* key_handle) { + TEE_Result res = TEE_SUCCESS; + TEE_Attribute attrs[4]; WTPI_AsymmetricKey_Handle sess = TEE_Malloc(sizeof(tee_asymmetric_key_handle), TEE_MALLOC_FILL_ZERO); if (sess == NULL) { @@ -123,7 +116,6 @@ static OEMCryptoResult Helper_CreateECCKeyHandle( return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - TEE_Result res = TEE_SUCCESS; rfc5915_eckey* sess_key = TEE_Malloc(sizeof(rfc5915_eckey), TEE_MALLOC_FILL_ZERO); if (sess_key == TEE_HANDLE_NULL) { @@ -155,9 +147,6 @@ static OEMCryptoResult Helper_CreateECCKeyHandle( goto cleanup; } - DMSG("Private key length is %d", sess_key->private_val_len); - - TEE_Attribute attrs[4]; TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, sess_key->private_val, sess_key->private_val_len); TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_X, @@ -216,13 +205,6 @@ OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( return OEMCrypto_ERROR_NOT_IMPLEMENTED; } -OEMCryptoResult WTPI_CreateTestRSAKeyHandle( - WTPI_AsymmetricKey_Handle* key_handle UNUSED) { - // TODO: wtpi_test_impl/crypto_interface has this unimplemented. What is - // it supposed to do? - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( WTPI_AsymmetricKey_Handle key_handle) { if (key_handle == TEE_HANDLE_NULL) { @@ -255,7 +237,7 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, if (padding_scheme == kSign_RSASSA_PSS) { // generate SHA1 digest uint8_t digest[20]; - TEE_OperationHandle sha1_op; + TEE_OperationHandle sha1_op = TEE_HANDLE_NULL; TEE_Result res = TEE_AllocateOperation(&sha1_op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0); if (res != TEE_SUCCESS) { @@ -280,7 +262,7 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sha1_op); - TEE_OperationHandle sign_op_handle; + TEE_OperationHandle sign_op_handle = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&sign_op_handle, TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1, TEE_MODE_SIGN, key_info.keySize); @@ -306,8 +288,60 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sign_op_handle); } else { - // TODO: add support for cast-specific RSA padding? - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + TEE_OperationHandle enc_op = TEE_HANDLE_NULL; + + // Allocate temp buffer to hold padded message. + uint8_t* temp_buf = + TEE_Malloc(key->max_signature_size, TEE_MALLOC_FILL_ZERO); + if (temp_buf == TEE_HANDLE_NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Pad in front of the message with block1 according to RFC 2313 + // 0x00 | 0x01 | 0xFF repeating | 0x00 | message + size_t temp_buf_len = key->max_signature_size; + temp_buf[0] = 0x00; + temp_buf[1] = 0x01; + TEE_MemFill(temp_buf + 2, 0xFF, temp_buf_len - 3 - message_length); + temp_buf[temp_buf_len - message_length - 1] = 0x00; + TEE_MemMove(temp_buf + temp_buf_len - message_length, message, + message_length); + + // Use NOPAD type, which ignores padding. Typically an operation wll either + // add padding (eg before encrypt) or expect to remove it (eg after + // decrypt). NOPAD just forces a raw RSA exponent+modulus operation. + uint32_t alg = TEE_ALG_RSA_NOPAD; + + // Using TEE_MODE_DECRYPT to use the private key in the RSA operation + TEE_Result res = TEE_AllocateOperation(&enc_op, alg, TEE_MODE_DECRYPT, + key->max_signature_size * 8); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation failed with result 0x%x", res); + TEE_Free(temp_buf); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + res = TEE_SetOperationKey(enc_op, key->key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + res = TEE_AsymmetricDecrypt(enc_op, NULL, 0, temp_buf, temp_buf_len, + signature, signature_length); + if (res != TEE_SUCCESS) { + EMSG("TEE_AsymmetricDecrypt failed with result 0x%x", res); + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_SUCCESS; } return OEMCrypto_SUCCESS; @@ -335,7 +369,7 @@ OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - TEE_OperationHandle decrypt_op_handle; + TEE_OperationHandle decrypt_op_handle = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&decrypt_op_handle, TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1, TEE_MODE_DECRYPT, key_info.keySize); @@ -373,20 +407,15 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, return OEMCrypto_SUCCESS; } -OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, - const uint8_t* message, size_t message_length, - uint8_t* signature, size_t* signature_length) { +OEMCryptoResult Helper_ECCSign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length, + bool der_encode) { RETURN_INVALID_CONTEXT_IF_NULL(key); RETURN_INVALID_CONTEXT_IF_NULL(message); RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(signature_length); - size_t max_signature_size = key->max_signature_size; - if (signature == NULL || *signature_length < max_signature_size) { - *signature_length = max_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - uint32_t sha_algo = 0; size_t sha_length = SHA512_DIGEST_LENGTH; uint32_t sign_algo = 0; @@ -394,18 +423,22 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, case TEE_ECC_CURVE_NIST_P224: sha_algo = TEE_ALG_SHA224; sign_algo = TEE_ALG_ECDSA_P224; + sha_length = 224 / 8; break; case TEE_ECC_CURVE_NIST_P256: sha_algo = TEE_ALG_SHA256; sign_algo = TEE_ALG_ECDSA_P256; + sha_length = 256 / 8; break; case TEE_ECC_CURVE_NIST_P384: sha_algo = TEE_ALG_SHA384; sign_algo = TEE_ALG_ECDSA_P384; + sha_length = 384 / 8; break; case TEE_ECC_CURVE_NIST_P521: sha_algo = TEE_ALG_SHA512; sign_algo = TEE_ALG_ECDSA_P521; + sha_length = 512 / 8; break; default: // Other curve types are not supported at this time. @@ -414,9 +447,19 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + size_t max_signature_size = key->max_signature_size; + if (!der_encode) { + max_signature_size = sha_length * 2; + } + if (signature == NULL || *signature_length < max_signature_size) { + *signature_length = max_signature_size; + EMSG("max_signature_size is %zu", max_signature_size); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // generate SHA digest uint8_t digest[SHA512_DIGEST_LENGTH]; - TEE_OperationHandle sha_op; + TEE_OperationHandle sha_op = TEE_HANDLE_NULL; TEE_Result res = TEE_AllocateOperation(&sha_op, sha_algo, TEE_MODE_DIGEST, 0); if (res != TEE_SUCCESS) { EMSG("TEE_AllocateOperation failed with result 0x%x", res); @@ -439,7 +482,7 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, TEE_FreeOperation(sha_op); // Sign digest - TEE_OperationHandle sign_op; + TEE_OperationHandle sign_op = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&sign_op, sign_algo, TEE_MODE_SIGN, key_info.keySize); if (res != TEE_SUCCESS) { @@ -464,11 +507,24 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sign_op); - // ASN1-encode the signature. - OEMCryptoResult encode_res = - EncodeECDSASignature(raw_sig, raw_sig_len, signature, signature_length); + OEMCryptoResult der_res = OEMCrypto_SUCCESS; + if (der_encode) { + // ASN1-encode the signature. + der_res = + EncodeECDSASignature(raw_sig, raw_sig_len, signature, signature_length); + } else { + TEE_MemMove(signature, raw_sig, raw_sig_len); + *signature_length = raw_sig_len; + } - return encode_res; + return der_res; +} + +OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length) { + return Helper_ECCSign(key, message, message_length, signature, + signature_length, true); } OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, @@ -480,6 +536,13 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_NULL(key_source); RETURN_INVALID_CONTEXT_IF_NULL(session_key_length); + rfc5915_eckey ecc_key = {0}; + TEE_OperationHandle ecdh_op = TEE_HANDLE_NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + TEE_Result res = TEE_SUCCESS; + TEE_Attribute attrs[2]; + TEE_ObjectHandle derived_key = TEE_HANDLE_NULL; + // Determine algorithm type and required key size based on incoming public key // curve parameters uint32_t alg_type = 0; @@ -511,9 +574,8 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, } // Allocate operation handle for ECDH - TEE_OperationHandle ecdh_op; - TEE_Result res = TEE_AllocateOperation(&ecdh_op, alg_type, TEE_MODE_DERIVE, - key_size_bytes * 8); + res = TEE_AllocateOperation(&ecdh_op, alg_type, TEE_MODE_DERIVE, + key_size_bytes * 8); if (res != TEE_SUCCESS) { EMSG("TEE_AllocateOperation failed with result 0x%x, %d", res, alg_type); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -529,26 +591,19 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, // Decode public key data into struct object defined by der_parse.h // This step will allocate memory for public key x and y values, so be sure to // free them - rfc5915_eckey ecc_key; - OEMCryptoResult result = - DecodeECCPublicKey(key_source, key_source_length, &ecc_key); + result = DecodeECCPublicKey(key_source, key_source_length, &ecc_key); if (result != OEMCrypto_SUCCESS) { EMSG("DecodeECCPublicKey failed with result 0x%x", res); goto cleanup; } // Copy public x and y values into attribute arrays - TEE_Attribute attrs[2]; TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, ecc_key.public_x, ecc_key.public_x_len); TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, ecc_key.public_y, ecc_key.public_y_len); - TEE_Free(ecc_key.public_x); - TEE_Free(ecc_key.public_y); - // Allocate object handle for derived key - TEE_ObjectHandle derived_key; res = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, 2048, &derived_key); if (res != TEE_SUCCESS) { @@ -568,150 +623,48 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, goto cleanup; } + TEE_Free(ecc_key.public_x); + TEE_Free(ecc_key.public_y); TEE_FreeOperation(ecdh_op); return OEMCrypto_SUCCESS; cleanup: + TEE_Free(ecc_key.public_x); + TEE_Free(ecc_key.public_y); TEE_FreeOperation(ecdh_op); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} +OEMCryptoResult WTPI_GetSignatureHashAlgorithm( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + RETURN_INVALID_CONTEXT_IF_NULL(key); + RETURN_INVALID_CONTEXT_IF_NULL(hash_algorithm); -OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( - AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length, uint8_t* public_key, - size_t* public_key_length) { - RETURN_INVALID_CONTEXT_IF_NULL(key_type); - RETURN_INVALID_CONTEXT_IF_NULL(wrapped_private_key_length); - RETURN_INVALID_CONTEXT_IF_NULL(public_key_length); + switch (key_type) { + case DRM_RSA_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA1; + return OEMCrypto_SUCCESS; - // This implementation generates RSA key. An alternative is ECC key. - *key_type = DRM_RSA_PRIVATE_KEY; + case DRM_ECC_PRIVATE_KEY: + switch (key->ecc_curve_type) { + case TEE_ECC_CURVE_NIST_P256: + *hash_algorithm = OEMCrypto_SHA2_256; + return OEMCrypto_SUCCESS; + case TEE_ECC_CURVE_NIST_P384: + *hash_algorithm = OEMCrypto_SHA2_384; + return OEMCrypto_SUCCESS; + case TEE_ECC_CURVE_NIST_P521: + *hash_algorithm = OEMCrypto_SHA2_512; + return OEMCrypto_SUCCESS; + default: + EMSG("Unsupported curve type %d", key->ecc_curve_type); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } - // Check buffer sizes. - size_t required_wrapped_private_key_length = 0; - OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( - PKCS8_2048BIT_RSA_KEY_MAX_SIZE, *key_type, - &required_wrapped_private_key_length); - if (result != OEMCrypto_SUCCESS) return result; - - const size_t required_public_key_length = KEY_SIZE_2048; - if (wrapped_private_key == NULL || - *wrapped_private_key_length < required_wrapped_private_key_length || - public_key == NULL || *public_key_length < required_public_key_length) { - *wrapped_private_key_length = required_wrapped_private_key_length; - *public_key_length = required_public_key_length; - return OEMCrypto_ERROR_SHORT_BUFFER; + case PROV40_ED25519_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA2_512; + return OEMCrypto_SUCCESS; } - - TEE_Result tee_res; - TEE_ObjectHandle key; - tee_res = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, KEY_SIZE_2048 * 8, - &key); - if (tee_res != TEE_SUCCESS) { - EMSG("TEE_AllocateTransientObject failed with result 0x%x", tee_res); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - tee_res = TEE_GenerateKey(key, KEY_SIZE_2048 * 8, NULL, 0); - if (tee_res != TEE_SUCCESS) { - EMSG("TEE_GenerateKey failed with result 0x%x", tee_res); - goto cleanup; - } - - // temporary buffers to hold the raw RSA data generated by GlobalPlatform - uint8_t raw_modulus[KEY_SIZE_2048]; - size_t raw_modulus_len = sizeof(raw_modulus); - uint8_t raw_pub[KEY_SIZE_2048]; - size_t raw_pub_len = sizeof(raw_pub); - uint8_t raw_priv[KEY_SIZE_2048]; - size_t raw_priv_len = sizeof(raw_priv); - - tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_MODULUS, raw_modulus, - &raw_modulus_len); - if (tee_res != TEE_SUCCESS) { - EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); - goto cleanup; - } - - tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_PUBLIC_EXPONENT, - raw_pub, &raw_pub_len); - if (tee_res != TEE_SUCCESS) { - EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); - goto cleanup; - } - - tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_PRIVATE_EXPONENT, - raw_priv, &raw_priv_len); - if (tee_res != TEE_SUCCESS) { - EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); - goto cleanup; - } - - pkcs1_rsa rsa_key = { - .modulus = raw_modulus, - .modulus_len = raw_modulus_len, - .public_exp = raw_pub, - .public_exp_len = raw_pub_len, - .private_exp = raw_priv, - .private_exp_len = raw_priv_len, - }; - - // Encode public key directly to output parameters - result = EncodeRSAPublicKey(&rsa_key, public_key, public_key_length); - if (result != OEMCrypto_SUCCESS) { - EMSG("EncodeRSAPublicKey failed"); - goto cleanup; - } - - // Encode private key to temporary buffer before wrapping - uint8_t encoded_priv[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE]; - size_t encoded_priv_len = MAX_WRAPPED_ASYMMETRIC_KEY_SIZE; - - result = EncodeRSAPrivateKey(&rsa_key, encoded_priv, &encoded_priv_len); - if (result != OEMCrypto_SUCCESS) { - EMSG("EncodeRSAPrivateKey failed"); - goto cleanup; - } - - // If the encoded key length is not a multiple of the AES block size, pad - // until it is. This is required for the WrapAsymmetricKey step - while (encoded_priv_len % AES_BLOCK_SIZE != 0 && - encoded_priv_len < MAX_WRAPPED_ASYMMETRIC_KEY_SIZE) { - encoded_priv[encoded_priv_len++] = 0; - } - - size_t required_size = 0; - result = WTPI_GetWrappedAsymmetricKeySize( - encoded_priv_len, DRM_RSA_PRIVATE_KEY, &required_size); - if (result != OEMCrypto_SUCCESS) { - EMSG("WTPI_GetWrappedAsymmetricKeySize failed with result %d", result); - goto cleanup; - } - *wrapped_private_key_length = required_size; - - result = - WTPI_WrapAsymmetricKey(wrapped_private_key, *wrapped_private_key_length, - *key_type, encoded_priv, encoded_priv_len); - if (result != OEMCrypto_SUCCESS) { - EMSG("WTPI_WrapAsymmetricKey failed with result %d", result); - goto cleanup; - } - - TEE_FreeTransientObject(key); - return OEMCrypto_SUCCESS; - -cleanup: - TEE_FreeTransientObject(key); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - -OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c index 363361d..fd0f62b 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c @@ -3,11 +3,12 @@ * source code may only be used and distributed under the Widevine * License Agreement. */ -#include #include #include #include +#include "crypto_common.h" #include "malloc.h" +#include "odk_endian.h" #include "oemcrypto_check_macros.h" #include "oemcrypto_key_types.h" #include "oemcrypto_math.h" @@ -16,10 +17,7 @@ #include "wtpi_abort_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_decrypt_sample_interface.h" - -OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key, - const uint8_t* input, - uint8_t* output); +#include "wtpi_secure_buffer_access_interface.h" static OEMCryptoResult WTPI_DecryptToOutputBuffer_CTR( WTPI_K1_SymmetricKey_Handle key, const uint8_t* initial_iv, @@ -41,19 +39,25 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CTR( return OEMCrypto_ERROR_INVALID_CONTEXT; } + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - uint8_t* const dest = out->buffer.clear_insecure + output_offset; uint8_t iv[AES_BLOCK_SIZE]; TEE_MemMove(iv, &initial_iv[0], AES_BLOCK_SIZE); size_t l = 0; while (l < size) { uint8_t aes_output[AES_BLOCK_SIZE]; - Helper_AESEncryptBlock_ECB(key, iv, aes_output); + const OEMCryptoResult result = + Helper_AESEncryptBlock_ECB(key, iv, aes_output); + if (result != OEMCrypto_SUCCESS) return result; for (uint8_t n = block_offset; n < AES_BLOCK_SIZE && l < size; ++n, ++l) { dest[l] = aes_output[n] ^ in[l]; } @@ -85,14 +89,21 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CBC( return OEMCrypto_ERROR_INVALID_CONTEXT; } - // TODO: somehow add support for secure buffers + // if (key->key_size != KEY_SIZE_128 || key->key_size != KEY_SIZE_256) { + // return OEMCrypto_ERROR_UNKNOWN_FAILURE; + // } + + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - uint8_t* const dest = out->buffer.clear_insecure + output_offset; const size_t pattern_length = pattern->encrypt + pattern->skip; uint8_t iv[AES_BLOCK_SIZE]; @@ -110,28 +121,14 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CBC( TEE_MemMove(&dest[offset], &in[offset], next_block_size); } else { uint8_t aes_output[AES_BLOCK_SIZE]; - /* Save the iv for the next block, in case |in| is in the same buffer as |dest|. */ TEE_MemMove(next_iv, &in[offset], AES_BLOCK_SIZE); - // TODO: check key size - - /* NOTE: the next few lines can be used instead of WTPI_AESCBCDecrypt, - * just to show parity with wtpi_test_impl implementation - */ - // OEMCryptoResult result = - // Helper_AESEncryptBlock_ECB(key, &in[offset], aes_output); - // if (result != OEMCrypto_SUCCESS) return result; - // for (size_t n = 0; n < AES_BLOCK_SIZE; n++) { - // dest[offset + n] = aes_output[n] ^ iv[n]; - // } - OEMCryptoResult result = WTPI_C1_AESCBCDecrypt( - key, KEY_SIZE_128, &in[offset], AES_BLOCK_SIZE, iv, aes_output); + key, key->key_size, &in[offset], AES_BLOCK_SIZE, iv, aes_output); if (result != OEMCrypto_SUCCESS) return result; TEE_MemMove(&dest[offset], aes_output, AES_BLOCK_SIZE); - TEE_MemMove(iv, next_iv, AES_BLOCK_SIZE); } offset += next_block_size; @@ -153,8 +150,8 @@ UBSAN_IGNORE_UNSIGNED_OVERFLOW static void AdvanceIVandCounter( /* The truncation here is intentional. */ const size_t increment = bytes / AES_BLOCK_SIZE; /* The potential overflow here is intentional. */ - counter = be64toh(counter) + increment; - counter = htobe64(counter); + counter = oemcrypto_be64toh(counter) + increment; + counter = oemcrypto_htobe64(counter); TEE_MemMove(&(*subsample_iv)[kCounterIndex], &counter, kCounterSize); } diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c index 6d93271..1a60282 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c @@ -60,6 +60,7 @@ static TEE_Result read_raw_object(const char* obj_id, size_t obj_id_length, TEE_ObjectHandle object; TEE_ObjectInfo object_info; TEE_Result res; + size_t read_bytes = 0; uint8_t* data = TEE_Malloc(out_length, 0); if (!data) return TEE_ERROR_OUT_OF_MEMORY; @@ -85,7 +86,6 @@ static TEE_Result read_raw_object(const char* obj_id, size_t obj_id_length, goto exit; } - size_t read_bytes = 0; res = TEE_ReadObjectData(object, data, object_info.dataSize, &read_bytes); if (res == TEE_SUCCESS) TEE_MemMove(out, data, read_bytes); if (res != TEE_SUCCESS || read_bytes != object_info.dataSize) { diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c new file mode 100644 index 0000000..5904403 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c @@ -0,0 +1,341 @@ +/* + * Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#include "asymmetric_key.h" +#include "cose_util.h" +#include "der_parse.h" +#include "oemcrypto_check_macros.h" +#include "opk_config.h" +#include "wtpi_abort_interface.h" +#include "wtpi_device_key_access_interface.h" +#include "wtpi_provisioning_4_interface.h" + +#define BCC_PAYLOAD_MAX_SIZE 2048 +#define COSE_SIGN1_MAX_SIZE 2048 + +OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( + AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length, uint8_t* public_key, + size_t* public_key_length) { + RETURN_INVALID_CONTEXT_IF_NULL(key_type); + RETURN_INVALID_CONTEXT_IF_NULL(wrapped_private_key_length); + RETURN_INVALID_CONTEXT_IF_NULL(public_key_length); + + // This implementation generates RSA key. An alternative is ECC key. + *key_type = DRM_RSA_PRIVATE_KEY; + + // temporary buffers to hold the raw RSA data generated by GlobalPlatform + uint8_t raw_modulus[KEY_SIZE_2048]; + size_t raw_modulus_len = sizeof(raw_modulus); + uint8_t raw_pub[KEY_SIZE_2048]; + size_t raw_pub_len = sizeof(raw_pub); + uint8_t raw_priv[KEY_SIZE_2048]; + size_t raw_priv_len = sizeof(raw_priv); + + TEE_Result tee_res = TEE_SUCCESS; + TEE_ObjectHandle key = TEE_HANDLE_NULL; + + pkcs1_rsa rsa_key = {0}; + + // Encode private key to temporary buffer before wrapping + uint8_t encoded_priv[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE]; + size_t encoded_priv_len = MAX_WRAPPED_ASYMMETRIC_KEY_SIZE; + + size_t required_size = 0; + + // Check buffer sizes. + size_t required_wrapped_private_key_length = 0; + OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( + PKCS8_2048BIT_RSA_KEY_MAX_SIZE, *key_type, + &required_wrapped_private_key_length); + if (result != OEMCrypto_SUCCESS) return result; + + // Public key size plus DER encoding overhead + const size_t required_public_key_length = KEY_SIZE_2048 + 38; + if (wrapped_private_key == NULL || + *wrapped_private_key_length < required_wrapped_private_key_length || + public_key == NULL || *public_key_length < required_public_key_length) { + *wrapped_private_key_length = required_wrapped_private_key_length; + *public_key_length = required_public_key_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + tee_res = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, KEY_SIZE_2048 * 8, + &key); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_AllocateTransientObject failed with result 0x%x", tee_res); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + tee_res = TEE_GenerateKey(key, KEY_SIZE_2048 * 8, NULL, 0); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GenerateKey failed with result 0x%x", tee_res); + goto cleanup; + } + + tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_MODULUS, raw_modulus, + &raw_modulus_len); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); + goto cleanup; + } + + tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_PUBLIC_EXPONENT, + raw_pub, &raw_pub_len); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); + goto cleanup; + } + + tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_PRIVATE_EXPONENT, + raw_priv, &raw_priv_len); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute failed with result 0x%x", tee_res); + goto cleanup; + } + + rsa_key.modulus = raw_modulus; + rsa_key.modulus_len = raw_modulus_len; + rsa_key.public_exp = raw_pub; + rsa_key.public_exp_len = raw_pub_len; + rsa_key.private_exp = raw_priv; + rsa_key.private_exp_len = raw_priv_len; + + // Encode public key directly to output parameters + result = EncodeRSAPublicKey(&rsa_key, public_key, public_key_length); + if (result != OEMCrypto_SUCCESS) { + EMSG("EncodeRSAPublicKey failed"); + goto cleanup; + } + + result = EncodeRSAPrivateKey(&rsa_key, encoded_priv, &encoded_priv_len); + if (result != OEMCrypto_SUCCESS) { + EMSG("EncodeRSAPrivateKey failed"); + goto cleanup; + } + + // If the encoded key length is not a multiple of the AES block size, pad + // until it is. This is required for the WrapAsymmetricKey step + while (encoded_priv_len % AES_BLOCK_SIZE != 0 && + encoded_priv_len < MAX_WRAPPED_ASYMMETRIC_KEY_SIZE) { + encoded_priv[encoded_priv_len++] = 0; + } + + result = WTPI_GetWrappedAsymmetricKeySize( + encoded_priv_len, DRM_RSA_PRIVATE_KEY, &required_size); + if (result != OEMCrypto_SUCCESS) { + EMSG("WTPI_GetWrappedAsymmetricKeySize failed with result %d", result); + goto cleanup; + } + *wrapped_private_key_length = required_size; + + result = + WTPI_WrapAsymmetricKey(wrapped_private_key, *wrapped_private_key_length, + *key_type, encoded_priv, encoded_priv_len); + if (result != OEMCrypto_SUCCESS) { + EMSG("WTPI_WrapAsymmetricKey failed with result %d", result); + goto cleanup; + } + + TEE_FreeTransientObject(key); + return OEMCrypto_SUCCESS; + +cleanup: + TEE_FreeTransientObject(key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +// Generate device-unique asymmetric key handle that is consistent across +// reboots. ECDSA +static OEMCryptoResult Helper_GetDeviceAsymmetricKeyIntoHandle( + AsymmetricKeyType* key_type, + WTPI_AsymmetricKey_Handle* private_key_handle) { + RETURN_INVALID_CONTEXT_IF_NULL(key_type); + RETURN_INVALID_CONTEXT_IF_NULL(private_key_handle); + + TEE_Attribute attrs[4]; + WTPI_AsymmetricKey_Handle sess = TEE_HANDLE_NULL; + TEE_Result res = TEE_SUCCESS; + OEMCryptoResult result = OEMCrypto_SUCCESS; + // Get device key + const uint8_t* device_key = WTPI_GetDeviceKey(); + const KeySize device_key_len = WTPI_GetDeviceKeySize(); + if (device_key == NULL || device_key_len == 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Use as seed to ECDSA + rfc5915_eckey* sess_key = + TEE_Malloc(sizeof(rfc5915_eckey), TEE_MALLOC_FILL_ZERO); + if (sess_key == TEE_HANDLE_NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + result = DeriveEccKey(device_key, device_key_len, TEE_ECC_CURVE_NIST_P256, + sess_key); + if (result != OEMCrypto_SUCCESS) { + goto cleanup; + } + + sess = TEE_Malloc(sizeof(tee_asymmetric_key_handle), TEE_MALLOC_FILL_ZERO); + if (sess == NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + sess->max_signature_size = sess_key->max_signature_size; + sess->ecc_curve_type = sess_key->ecc_curve_type; + + res = TEE_AllocateTransientObject( + TEE_TYPE_ECDSA_KEYPAIR, sess_key->private_val_len * 8, &sess->key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); + goto cleanup; + } + + TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, + sess_key->private_val, sess_key->private_val_len); + TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_X, + sess_key->public_x, sess_key->public_x_len); + TEE_InitRefAttribute(&attrs[2], TEE_ATTR_ECC_PUBLIC_VALUE_Y, + sess_key->public_y, sess_key->public_y_len); + TEE_InitValueAttribute(&attrs[3], TEE_ATTR_ECC_CURVE, + sess_key->ecc_curve_type, 0); + + res = TEE_PopulateTransientObject(sess->key_handle, + (const TEE_Attribute*)(&attrs), 4); + if (res != TEE_SUCCESS) { + EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); + goto cleanup; + } + + *key_type = DRM_ECC_PRIVATE_KEY; + +cleanup: + if (sess_key != TEE_HANDLE_NULL) { + TEE_Free(sess_key->private_val); + TEE_Free(sess_key->public_x); + TEE_Free(sess_key->public_y); + } + TEE_Free(sess_key); + + if (res != TEE_SUCCESS) { + WTPI_FreeAsymmetricKeyHandle(sess); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + *private_key_handle = sess; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_BccKeyCoseSign1(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) { + RETURN_INVALID_CONTEXT_IF_NULL(message); + RETURN_INVALID_CONTEXT_IF_ZERO(message_length); + RETURN_INVALID_CONTEXT_IF_NULL(signature_length); + + if (message_length > 500) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + // 64 bytes for ECDSA signature, 11 bytes for CBOR fields + size_t required_signature_length = message_length + 64 + 11; + if (signature == NULL || *signature_length < required_signature_length) { + *signature_length = required_signature_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + // Generate ECDSA key, using device key as seed + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + OEMCryptoResult result = + Helper_GetDeviceAsymmetricKeyIntoHandle(&key_type, &private_key_handle); + if (result != OEMCrypto_SUCCESS) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // CoseSign1 message using ECDSA key + size_t encoded_size = 0; + result = DiceCoseSignAndEncodeSign1(message, message_length, key_type, + private_key_handle, *signature_length, + signature, &encoded_size); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + + *signature_length = encoded_size; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetMaxBccKeyCoseSign1Size(size_t* out_length) { + RETURN_INVALID_CONTEXT_IF_NULL(out_length); + *out_length = COSE_SIGN1_MAX_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // The |out| buffer length check is delegated to the BuildBootCertificateChain + // call below. + + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + OEMCryptoResult result = + Helper_GetDeviceAsymmetricKeyIntoHandle(&key_type, &private_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + + // Only ECDSA key is expected for now. + if (key_type != DRM_ECC_PRIVATE_KEY) { + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + // extract public key, P256 hardcoded to 64 bytes long + uint8_t public_key[64]; + size_t public_key_length = sizeof(public_key); + size_t buf_size = 32; + TEE_Result tee_res = TEE_GetObjectBufferAttribute( + private_key_handle->key_handle, TEE_ATTR_ECC_PUBLIC_VALUE_X, public_key, + &buf_size); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute() failed with result 0x%x", tee_res); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + tee_res = TEE_GetObjectBufferAttribute(private_key_handle->key_handle, + TEE_ATTR_ECC_PUBLIC_VALUE_Y, + public_key + 32, &buf_size); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute() failed with result 0x%x", tee_res); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + result = BuildBootCertificateChain(public_key, public_key_length, key_type, + private_key_handle, out, out_length); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return result; +} + +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + RETURN_INVALID_CONTEXT_IF_NULL(out_length); + *out_length = BCC_PAYLOAD_MAX_SIZE; + return OEMCrypto_SUCCESS; +} + +// For cose utility +// CBOR ECDSA signatures should not be DER encoded, just concatenated (R,S) +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type UNUSED, + const uint8_t* message, size_t message_size, + uint8_t* signature, size_t* signature_length) { + return Helper_ECCSign(key, message, message_size, signature, signature_length, + false); +} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c index 8ca08d5..5fc4f0d 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c @@ -9,7 +9,9 @@ #include #include #include +#include +#include "cose_util.h" #include "odk_endian.h" #include "oemcrypto_key_types.h" #include "renewal_util.h" @@ -19,6 +21,7 @@ #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_device_renewal_interface_layer1.h" #include "wtpi_logging_interface.h" +#include "wtpi_provisioning_4_interface.h" // This layer keeps a copy of the keybox in volatile memory. A more secure // implementation of this would only keep the device key in memory while it is @@ -178,9 +181,60 @@ OEMCryptoResult WTPI_ValidateKeybox(void) { return OEMCrypto_SUCCESS; } +static OEMCryptoResult GetProv4DeviceID(uint8_t* device_id, + size_t device_id_length) { + if (device_id == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (device_id_length < SHA256_DIGEST_LENGTH) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + size_t required_bcc_payload_size = 0; + OEMCryptoResult result = + WTPI_GetMaxBootCertificateChainSize(&required_bcc_payload_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max bcc size: %u", result); + return result; + } + + // Device ID with provisioning 4 in this reference implementation is hash of + // (encoded) device public key from BCC. + uint8_t* bcc_buffer = (uint8_t*)TEE_Malloc(required_bcc_payload_size, 0); + if (bcc_buffer == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + memset(bcc_buffer, 0, required_bcc_payload_size); + size_t bcc_size = required_bcc_payload_size; + result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); + if (result != OEMCrypto_SUCCESS) { + TEE_Free(bcc_buffer); + return result; + } + + uint8_t* dk_pub_buffer = (uint8_t*)TEE_Malloc(required_bcc_payload_size, 0); + if (dk_pub_buffer == NULL) { + TEE_Free(bcc_buffer); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(dk_pub_buffer, 0, required_bcc_payload_size); + size_t dk_pub_size = required_bcc_payload_size; + result = GetDevicePublicKeyFromBcc(bcc_buffer, bcc_size, dk_pub_buffer, + &dk_pub_size); + TEE_Free(bcc_buffer); + if (result != OEMCrypto_SUCCESS) { + TEE_Free(dk_pub_buffer); + return result; + } + + result = WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + TEE_Free(dk_pub_buffer); + return result; +} + OEMCryptoResult WTPI_GetDeviceID(uint8_t* device_id, size_t device_id_length) { if (device_id == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (WTPI_GetProvisioningMethod() == OEMCrypto_BootCertificateChain) { + return GetProv4DeviceID(device_id, device_id_length); + } + if (WTPI_GetProvisioningMethod() != OEMCrypto_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -196,7 +250,9 @@ OEMCryptoResult WTPI_GetDeviceIDLength(size_t* device_id_length) { if (device_id_length == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (WTPI_GetProvisioningMethod() == OEMCrypto_Keybox) { + if (WTPI_GetProvisioningMethod() == OEMCrypto_BootCertificateChain) { + *device_id_length = SHA256_DIGEST_LENGTH; + } else if (WTPI_GetProvisioningMethod() == OEMCrypto_Keybox) { *device_id_length = KEYBOX_DEVICE_ID_SIZE; } else { return OEMCrypto_ERROR_NOT_IMPLEMENTED; diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile index 803a114..4729e6f 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile @@ -35,4 +35,4 @@ endif .DEFAULT_GOAL := build_and_copy .PHONY: build_and_copy build_and_copy: all - -cp $(O)/*.{elf,ta,dmp,map} $(O_BASE)/ + cp $(O)/$(BINARY).ta $(O_BASE)/ diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c index b442337..1f0818e 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c @@ -100,7 +100,7 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { size_t request_size = params[1].memref.size; if (request_size > OPK_TRANSPORT_MESSAGE_SIZE) { - DMSG("Size too large. Input is %d, limit is %d\n", request_size, + DMSG("Size too large. Input is %zu, limit is %d\n", request_size, OPK_TRANSPORT_MESSAGE_SIZE); return TEE_ERROR_BAD_PARAMETERS; } diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk index cee202f..42c1fac 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk @@ -25,7 +25,8 @@ include $(CDM_DIR)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk # srcs-y, global-incdirs-y, and libnames are used by the OP-TEE TA dev kit # build system srcs-y += \ - oemcrypto_ta.c \ + oemcrypto_ta.c \ + $(serialization_dir)/tee/tee_tos_stubs.c \ $(opk_base_ta_sources) \ $(wtpi_impl_sources) \ @@ -35,6 +36,15 @@ global-incdirs-y += \ cppflags-y += \ -DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \ + -DOPK_CONFIG_SOC_VENDOR_NAME=$(SOC_VENDOR) \ + -DOPK_CONFIG_SOC_MODEL_NAME=$(SOC_MODEL) \ + -DOPK_CONFIG_TEE_OS_NAME=$(TEE_OS) \ + -DOPK_CONFIG_TEE_OS_VERSION=$(TEE_VERSION) \ + -DOPK_CONFIG_DEVICE_FORM_FACTOR=$(DEVICE_FORM_FACTOR) \ + -DOPK_CONFIG_IMPLEMENTER_NAME=$(IMPLEMENTER) \ + -Wno-switch-default + + #-D_DEBUG libnames += \ $(wtpi_impl_libs) diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile index 580531b..a25f452 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile @@ -35,4 +35,4 @@ endif .DEFAULT_GOAL := build_and_copy .PHONY: build_and_copy build_and_copy: all - -cp $(O)/*.{elf,ta,dmp,map} $(O_BASE)/ + cp $(O)/$(BINARY).ta $(O_BASE)/ diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk index 540dcb7..5a685d8 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk @@ -38,3 +38,12 @@ global-incdirs-y += \ libnames += \ $(wtpi_impl_libs) + +cppflags-y += \ + -DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \ + -DOPK_CONFIG_SOC_VENDOR_NAME=$(SOC_VENDOR) \ + -DOPK_CONFIG_SOC_MODEL_NAME=$(SOC_MODEL) \ + -DOPK_CONFIG_TEE_OS_NAME=$(TEE_OS) \ + -DOPK_CONFIG_TEE_OS_VERSION=$(TEE_VERSION) \ + -DOPK_CONFIG_DEVICE_FORM_FACTOR=$(DEVICE_FORM_FACTOR) \ + -DOPK_CONFIG_IMPLEMENTER_NAME=$(IMPLEMENTER) \ diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c index c13a98f..02cdd8f 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c @@ -94,7 +94,7 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { size_t request_size = params[1].memref.size; if (request_size > OPK_TRANSPORT_MESSAGE_SIZE) { - DMSG("Size too large. Input is %d, limit is %d\n", request_size, + DMSG("Size too large. Input is %zu, limit is %d\n", request_size, OPK_TRANSPORT_MESSAGE_SIZE); return TEE_ERROR_BAD_PARAMETERS; } @@ -106,7 +106,7 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { static uint8_t local_buffer[OPK_TRANSPORT_MESSAGE_SIZE]; memcpy(local_buffer, transport_buffer_, request_size); - DMSG("Request size is %d\n", request_size); + DMSG("Request size is %zu\n", request_size); ODK_Message request = ODK_Message_Create(local_buffer, request_size); ODK_Message_SetSize(&request, request_size); ODK_Message response; diff --git a/oemcrypto/opk/ports/trusty/ta/README.md b/oemcrypto/opk/ports/trusty/ta/README.md index c26280d..45b4493 100644 --- a/oemcrypto/opk/ports/trusty/ta/README.md +++ b/oemcrypto/opk/ports/trusty/ta/README.md @@ -25,7 +25,7 @@ desired, the individual OEMCrypto TA ELF file can be found relative to the `user_tasks` folder, depending on the location of the Trusty codebase relative to the CDM folder. For example, if the CDM repo can be reached from Trusty by going up two directories, then the OEMCrypto TA build output will be two -directories up from the `user_tasks` folder. +directories up from the `user_tasks` folder. The project name can be changed to other supported formats, provided that the OEMCrypto TA path is added to the appropriate makefile. Type `make list` at the @@ -39,17 +39,15 @@ repo sync -c -j32 # Download an Android NDK prebuilt to compile liboemcrypto.so cd $TRUSTY_DIR/prebuilts -git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r21 ndk +mkdir -p ndk && cd ndk +git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r21 r21 # 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, eg -# "../../cdm/oemcrypto/opk/ports/trusty/ta" +# to a path that is relative to the Trusty directory +OEMCRYPTO_TA_DIR=../../oemcrypto/opk/ports/trusty/ta/reference cd $TRUSTY_DIR/trusty/device/arm/generic-arm64/project sed -i "/TRUSTY_BUILTIN_USER_TASKS/a ${OEMCRYPTO_TA_DIR} \\\\" generic-arm-inc.mk -# Add a required build variable -echo "WIDEVINE_PROVISION_METHOD := 2" >> generic-arm-inc.mk - # Run the build script. `make $TRUSTY_PROJECT` from the top level is also # sufficient TRUSTY_PROJECT=qemu-generic-arm64-test-debug diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0.c deleted file mode 100644 index 5e4bc99..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2022 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. - */ -#define TLOG_TAG "DEVICEKEY_V0" - -#include "device_key_v0_interface.h" - -#include -#include -#include -#include -#include -#include - -#include "wtpi_crypto_and_key_management_interface_layer1.h" -#include "wtpi_device_key_interface.h" - -/** Legacy context value used for signing the private key in the DRM - * certificate. This should be used as a key derivation context in - * DeriveDeviceKeyIntoHandle_V0() for unwrapping the DRM key in the old format. - * Do not change. - */ -#define DEVICE_KEY_SIGN_DRM_CERT 0x85a65596 - -#define MAX_KEY_SIZE 32 - -static const uint8_t DERIVATION_DATA[MAX_KEY_SIZE + 1] = - "....TrustyWidevineDerivationData"; - -/* Structure for holding a wrapped RSA key in old format used on Pixel 6. It - contains the encrypted RSA key plus a header containing the non-secret info - needed to decrypt it. The size of the key is not known at compile-time, so it - is stored in a Flexible Array Member. Note that the code that uses this - struct relies on the signature being the first field when calculating the - signature. */ -typedef struct WrappedRSAKey_V0 { - uint8_t signature[MAC_KEY_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - uint8_t enc_rsa_key[]; -} WrappedRSAKey_V0; - -static void generate_derivation_data(uint32_t context, - uint8_t* data, - size_t data_len) { - assert(data != NULL); - - /* - * The varying data must be included in the derivation data. - * Unfortunately the low-level key derivation interface requires the - * derivation data to be equal to the output key size, and we can generate - * two different key sizes. - * It's OK to truncate the constant part on smaller keys. - */ - assert(data_len > 4); - - /* Initialize with a constant payload. */ - memcpy(data, DERIVATION_DATA, data_len); - - /* Set the first four bytes to the specific use for this key. */ - memcpy(data, &context, sizeof(context)); -} - -static long derive_key(uint8_t* derivation_data, - uint8_t* key, - size_t key_size) { - long rc = hwkey_open(); - if (rc < 0) { - return rc; - } - hwkey_session_t session = (hwkey_session_t)rc; - uint32_t kdf_version = HWKEY_KDF_VERSION_1; - rc = hwkey_derive(session, &kdf_version, derivation_data, key, key_size); - hwkey_close(session); - return rc; -} - -static OEMCryptoResult DeriveDeviceKeyIntoHandle_V0( - uint32_t context, - SymmetricKeyType out_key_type, - WTPI_K1_SymmetricKey_Handle* out_key_handle, - KeySize out_key_size) { - assert(out_key_handle != NULL); - if (out_key_size > MAX_KEY_SIZE) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - uint8_t derivation_data[MAX_KEY_SIZE]; - generate_derivation_data(context, derivation_data, out_key_size); - - uint8_t key_data[MAX_KEY_SIZE]; - if (derive_key(derivation_data, key_data, out_key_size) < 0) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - OEMCryptoResult result = WTPI_K1_CreateKeyHandle( - key_data, (size_t)out_key_size, out_key_type, out_key_handle); - - /* Wipe the key off the stack. */ - memset(key_data, 0, sizeof(key_data)); - - return result; -} - -OEMCryptoResult VerifyAndDecryptDRMKeyData_V0(const uint8_t* wrapped, - size_t wrapped_size, - uint8_t* out) { - if (wrapped == NULL || wrapped_size == 0 || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (wrapped_size < sizeof(WrappedRSAKey_V0)) { - TLOGE("wrapped rsa key length is too short."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const size_t enc_rsa_key_length = wrapped_size - sizeof(WrappedRSAKey_V0); - if (enc_rsa_key_length > PKCS8_RSA_KEY_MAX_SIZE) { - TLOGE("wrapped rsa key length is too long."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const WrappedRSAKey_V0* wrapped_key = (const WrappedRSAKey_V0*)(wrapped); - WTPI_K1_SymmetricKey_Handle signing_key = NULL; - OEMCryptoResult result = DeriveDeviceKeyIntoHandle_V0( - DEVICE_KEY_SIGN_DRM_CERT, MAC_KEY_SERVER, &signing_key, - KEY_SIZE_256); - if (result != OEMCrypto_SUCCESS) { - WTPI_K1_FreeKeyHandle(signing_key); - return result; - } - const size_t offset = sizeof(wrapped_key->signature); - result = WTPI_C1_HMAC_SHA256_Verify(signing_key, wrapped + offset, - wrapped_size - offset, - wrapped_key->signature); - WTPI_K1_FreeKeyHandle(signing_key); - if (result != OEMCrypto_SUCCESS) - return result; - WTPI_K1_SymmetricKey_Handle encryption_key = NULL; - result = DeriveDeviceKeyIntoHandle_V0(DEVICE_KEY_WRAP_DRM_CERT, - ENCRYPTION_KEY, &encryption_key, - KEY_SIZE_128); - if (result != OEMCrypto_SUCCESS) { - WTPI_K1_FreeKeyHandle(encryption_key); - return result; - } - result = WTPI_C1_AESCBCDecrypt(encryption_key, KEY_SIZE_128, - wrapped_key->enc_rsa_key, enc_rsa_key_length, - wrapped_key->iv, out); - WTPI_K1_FreeKeyHandle(encryption_key); - return result; -} - -OEMCryptoResult VerifyAndDecryptUsageData_V0(const uint8_t* wrapped, - size_t wrapped_size, - const uint8_t* signature, - const uint8_t* iv, - uint8_t* out) { - if (wrapped == NULL || wrapped_size == 0 || signature == NULL || - iv == NULL || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - WTPI_K1_SymmetricKey_Handle signing_key = NULL; - /* Ideally the context for deriving signing_key below should be - * DEVICE_KEY_SIGN_USAGE_TABLE but not DEVICE_KEY_WRAP_USAGE_TABLE. However, - * the latter was used in the legacy code to sign DRM key, which is already - * in production. This could be a bug we overlooked when the code was - * merged. To work with the existing wrapped key on these devices, we have - * to stick to DEVICE_KEY_WRAP_USAGE_TABLE. */ - OEMCryptoResult result = DeriveDeviceKeyIntoHandle_V0( - DEVICE_KEY_WRAP_USAGE_TABLE, MAC_KEY_SERVER, &signing_key, - KEY_SIZE_256); - if (result != OEMCrypto_SUCCESS) { - TLOGE("Failed to derive signing key with result: %u", result); - WTPI_K1_FreeKeyHandle(signing_key); - return result; - } - result = WTPI_C1_HMAC_SHA256_Verify(signing_key, wrapped, wrapped_size, - signature); - WTPI_K1_FreeKeyHandle(signing_key); - if (result != OEMCrypto_SUCCESS) - return result; - WTPI_K1_SymmetricKey_Handle encryption_key = NULL; - result = DeriveDeviceKeyIntoHandle_V0(DEVICE_KEY_WRAP_USAGE_TABLE, - ENCRYPTION_KEY, &encryption_key, - KEY_SIZE_128); - if (result != OEMCrypto_SUCCESS) { - WTPI_K1_FreeKeyHandle(encryption_key); - return result; - } - result = WTPI_C1_AESCBCDecrypt(encryption_key, KEY_SIZE_128, wrapped, - wrapped_size, iv, out); - WTPI_K1_FreeKeyHandle(encryption_key); - return result; -} \ No newline at end of file diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0_interface.h b/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0_interface.h deleted file mode 100644 index 354a286..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/device_key_v0_interface.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 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 "OEMCryptoCENCCommon.h" - -OEMCryptoResult VerifyAndDecryptDRMKeyData_V0(const uint8_t* wrapped, - size_t wrapped_size, - uint8_t* out); - -OEMCryptoResult VerifyAndDecryptUsageData_V0(const uint8_t* wrapped, - size_t wrapped_size, - const uint8_t* signature, - const uint8_t* iv, - uint8_t* out); diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_config.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_config.c deleted file mode 100644 index 5cdd626..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_config.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2021 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 - -OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) { - return OEMCrypto_Level1; -} - -/* - * WIDEVINE_PROVISION_METHOD is a mandatory variable set by the platform's build - * file (*-inc.mk) - */ -OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { -#if WIDEVINE_PROVISION_METHOD == 2 - return OEMCrypto_Keybox; -#elif WIDEVINE_PROVISION_METHOD == 4 - return OEMCrypto_BootCertificateChain; -#else -#error message "Unsupported provisioning method." -#endif -} - -uint32_t WTPI_GetResourceRatingTier(void) { - return 3; -} - -uint32_t TEE_GetRSAPaddingSchemes(void) { - return kSign_RSASSA_PSS ^ kSign_PKCS1_Block1; -} - -OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) { - if (srm_version == NULL) - return OEMCrypto_ERROR_INVALID_CONTEXT; - *srm_version = 0; - return OEMCrypto_SUCCESS; -} - -bool WTPI_IsAntiRollbackHWPresent() { - return false; -} - -OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field) { - /* No CGMS for test impl. */ - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -bool WTPI_IsCGMS_AActive(void) { - return false; -} - -bool WTPI_SupportsCGMS_A(void) { - return false; -} - -bool WTPI_HasAnalogDisplay(void) { - return false; -} - -bool WTPI_IsAnalogDisplayActive(void) { - return false; -} - -bool WTPI_CanDisableAnalogDisplay(void) { - return false; -} - -bool WTPI_DisableAnalogDisplay(void) { - return false; -} - -size_t WTPI_MaxOutputSizeForDecrypt(void) { - return 0; /* Unrestricted. */ -} - -bool WTPI_IsClosedPlatform(void) { - return false; -} - -OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { - return HDCP_NO_DIGITAL_OUTPUT; -} - -OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) { - return HDCP_NO_DIGITAL_OUTPUT; -} - -size_t WTPI_MaxBufferSizeForGenericCrypto(void) { - return 500 * 1024; /* 500 KiB according to resource rating tier. */ -} - -size_t WTPI_MaxSampleSize(void) { - return 16 * 1024 * 1024; /* 16 MiB according to resource rating tier. */ -} - -uint32_t WTPI_SupportedCertificates(void) { - return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit; -} - -bool WTPI_IsProductionReady(void) { - // TODO(b/224065807): revisit this for checking for production readiness - return true; -} - -OEMCrypto_DTCP2_Capability WTPI_GetDTCP2Capability(void) { - return OEMCrypto_NO_DTCP2; -} - -OEMCrypto_WatermarkingSupport WTPI_GetWatermarkingSupport(void) { - return OEMCrypto_WatermarkingNotSupported; -} - -OPK_FeatureStatus WTPI_IsTAAntiRollbackEnabled(void) { - // TODO(b/224065807): revisit this for checking for production readiness - return OPK_FEATURE_NOT_SUPPORTED; -} diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c deleted file mode 100644 index 36ce71b..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Copyright (C) 2021 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_crypto_and_key_management_interface_layer1.h" - -#include -#include -#include -#include /* THIS IS TEMPORARY UNTIL WE GET AN ALLOCATOR. */ -#include - -#include "OEMCryptoCENCCommon.h" -#include "crypto_util.h" -#include "oemcrypto_compiler_attributes.h" -#include "oemcrypto_object_table.h" -#include "oemcrypto_overflow.h" -#include "openssl/rand.h" -#include "openssl/x509.h" -#include "wtpi_abort_interface.h" -#include "wtpi_config_macros.h" -#include "wtpi_device_key_interface.h" -#include "wtpi_logging_interface.h" -#include "wtpi_secure_buffer_access_interface.h" - -/****************************************************************************** - * This is a reference implementation of Crypto and Key Management layer 1, - * using OpenSSL/BoringSSL. The keys in this layer are encrypted and signed by a - * device specific key, and are stored in a pre-allocated table. - ******************************************************************************/ - -/** Wrapped key data to be saved in key management layer 1 table. */ -typedef struct WrappedKeyData { - uint8_t iv[KEY_IV_SIZE]; - uint8_t wrapped_key[MAX_WRAPPED_SYMMETRIC_KEY_SIZE]; -} WrappedKeyData; - -/** Signed and wrapped key data to be saved in key management layer 1 table. */ -typedef struct SignedWrappedKeyData { - uint8_t signature[SHA256_DIGEST_LENGTH]; - WrappedKeyData wrapped_key_data; -} SignedWrappedKeyData; - -typedef struct WTPI_K1_SymmetricKey { - SymmetricKeyType key_type; - KeySize key_size; - SignedWrappedKeyData key_data; -} WTPI_K1_SymmetricKey; - -typedef struct wtpi_k1_symmetric_key_handle { - uint32_t index; - bool is_key_cached; - uint8_t cached_key[KEY_SIZE_256]; -} wtpi_k1_symmetric_key_handle; - -/** - * Key table used by key management layer 1. Keys in the table are wrapped by a - * device specific key. When being used, the key needs to be unwrapped and - * verified first. - */ -DEFINE_OBJECT_TABLE(key_table, WTPI_K1_SymmetricKey, MAX_NUMBER_OF_KEYS, NULL); - -static bool IsKeyValid(uint32_t index) { - WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, index); - switch (key->key_type) { - case CONTENT_KEY: - // We cheat a little here. We also call generic crypto keys "content - // keys", even though some of them are 256 bit HMAC keys. - return key->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256; - case ENTITLEMENT_KEY: - case MAC_KEY_SERVER: - case MAC_KEY_CLIENT: - return key->key_size == KEY_SIZE_256; - case ENCRYPTION_KEY: - return key->key_size == KEY_SIZE_128; - case DERIVING_KEY: - return key->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256; - } -} - -static bool IsKeyHandleValid(WTPI_K1_SymmetricKey_Handle key_handle) { - if (key_handle == NULL || key_handle->index >= MAX_NUMBER_OF_KEYS || - !IsKeyValid(key_handle->index)) { - return false; - } - if (!key_handle->is_key_cached) { - for (size_t i = 0; i < sizeof(key_handle->cached_key); i++) { - if (key_handle->cached_key[i] != 0) - return false; - } - } - return true; -} - -static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle, - SymmetricKeyType* type) { - if (key_handle == NULL || type == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - WTPI_K1_SymmetricKey* key = - OPKI_GetFromObjectTable(&key_table, key_handle->index); - *type = key->key_type; - return OEMCrypto_SUCCESS; -} - -/****************************************************************************** - * Trusty specific device key derivation - ******************************************************************************/ - -#define MAX_KEY_SIZE 32 - -static const uint8_t DERIVATION_DATA[MAX_KEY_SIZE + 1] = - "..........TrustyWvDerivationData"; - -static void generate_derivation_data(uint32_t context, - uint32_t key_type, - uint8_t* data, - size_t data_len) { - assert(data != NULL); - - /* - * The varying data must be included in the derivation data. - * Unfortunately the low-level key derivation interface requires the - * derivation data to be equal to the output key size, and we can generate - * two different key sizes. - * It's OK to truncate the constant part on smaller keys. - */ - assert(data_len > 4); - - /* Initialize with a constant payload. */ - memcpy(data, DERIVATION_DATA, data_len); - - /* Set the first four bytes to the specific use for this key. */ - memcpy(data, &context, sizeof(context)); - - /* Set the next four bytes to the key type. */ - memcpy(data + sizeof(context), &key_type, sizeof(key_type)); -} - -static long derive_key(uint8_t* derivation_data, - uint8_t* key, - size_t key_size) { - long rc = hwkey_open(); - if (rc < 0) { - return rc; - } - hwkey_session_t session = (hwkey_session_t)rc; - uint32_t kdf_version = HWKEY_KDF_VERSION_1; - rc = hwkey_derive(session, &kdf_version, derivation_data, key, key_size); - hwkey_close(session); - return rc; -} - -static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, - SymmetricKeyType out_key_type, - uint8_t* out_key, - KeySize out_key_size) { - ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); - ABORT_IF(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256, - "Invalid key size"); - - // Prepare full context for key derivation - // Server and client MAC keys must derive to the same key. - const SymmetricKeyType type_temp = - out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type; - // Cast the type into 32 bits so it is the same size as the gap left for it - // in full_context. This will be a no-op on most architectures. - const uint32_t type_32 = (uint32_t)type_temp; - - uint8_t derivation_data[MAX_KEY_SIZE]; - generate_derivation_data(context, type_32, derivation_data, - (size_t)out_key_size); - - if (derive_key(derivation_data, out_key, (size_t)out_key_size) < 0) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -/****************************************************************************** - * End Trusty specific device key derivation - ******************************************************************************/ - -static OEMCryptoResult EncryptAndSignKey(const uint8_t* key, - size_t key_size, - uint8_t* out, - size_t out_size) { - ABORT_IF(key == NULL || key_size == 0 || out == NULL, - "Parameters are NULL or 0"); - ABORT_IF(out_size < sizeof(SignedWrappedKeyData), - "Invalid output buffer size"); - - SignedWrappedKeyData* wrapped = (SignedWrappedKeyData*)out; - /* Pick a random IV for generating keys. */ - OEMCryptoResult result = WTPI_C1_RandomBytes( - wrapped->wrapped_key_data.iv, sizeof(wrapped->wrapped_key_data.iv)); - if (result != OEMCrypto_SUCCESS) - return result; - - // Encrypt the key - uint8_t encryption_key[KEY_SIZE_128]; - result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, ENCRYPTION_KEY, - encryption_key, - OPK_LengthToKeySize(sizeof(encryption_key))); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_AESCBCEncrypt(key, key_size, wrapped->wrapped_key_data.iv, - encryption_key, sizeof(encryption_key), - wrapped->wrapped_key_data.wrapped_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // Compute the signature of the wrapped key and store it - uint8_t signing_key[KEY_SIZE_256]; - result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_CLIENT, - signing_key, - OPK_LengthToKeySize(sizeof(signing_key))); - if (result != OEMCrypto_SUCCESS) - return result; - const uint8_t* wrapped_key_data = - (const uint8_t*)(&wrapped->wrapped_key_data); - size_t wrapped_key_data_length = sizeof(wrapped->wrapped_key_data); - if (!OPKI_HMAC_SHA256(wrapped_key_data, wrapped_key_data_length, - signing_key, sizeof(signing_key), - wrapped->signature)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return result; -} - -static OEMCryptoResult VerifyAndDecryptKey( - WTPI_K1_SymmetricKey_Handle key_handle, - uint8_t* out_key, - size_t out_size) { - ABORT_IF(!IsKeyHandleValid(key_handle), "Impossible key handle."); - ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); - WTPI_K1_SymmetricKey* key = - OPKI_GetFromObjectTable(&key_table, key_handle->index); - if (key == NULL) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - ABORT_IF(out_size < (size_t)(key->key_size), "Invalid output buffer size"); - - const uint8_t* wrapped_data = (const uint8_t*)(&key->key_data); - if (wrapped_data == NULL) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - const SignedWrappedKeyData* wrapped = - (const SignedWrappedKeyData*)wrapped_data; - - // Verify the signature first, before decrypting - uint8_t signing_key[KEY_SIZE_256]; - OEMCryptoResult result = DeriveFromDeviceKey( - DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_SERVER, signing_key, - OPK_LengthToKeySize(sizeof(signing_key))); - if (result != OEMCrypto_SUCCESS) - return result; - const uint8_t* wrapped_key_data = - (const uint8_t*)(&wrapped->wrapped_key_data); - size_t wrapped_key_data_length = sizeof(wrapped->wrapped_key_data); - uint8_t computed_signature[SHA256_DIGEST_LENGTH]; - if (!OPKI_HMAC_SHA256(wrapped_key_data, wrapped_key_data_length, - signing_key, sizeof(signing_key), - computed_signature)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (memcmp(wrapped->signature, computed_signature, SHA256_DIGEST_LENGTH) != - 0) { - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Decrypt the key - uint8_t decryption_key[KEY_SIZE_128]; - result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, ENCRYPTION_KEY, - decryption_key, - OPK_LengthToKeySize(sizeof(decryption_key))); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_AESCBCDecrypt(wrapped->wrapped_key_data.wrapped_key, - (size_t)(key->key_size), - wrapped->wrapped_key_data.iv, decryption_key, - sizeof(decryption_key), out_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -/* Caller to ensure the inputs are valid. */ -static OEMCryptoResult PrepareCachedKey(WTPI_K1_SymmetricKey_Handle key_handle, - size_t size) { - if (key_handle->is_key_cached) - return OEMCrypto_SUCCESS; - OEMCryptoResult result = - VerifyAndDecryptKey(key_handle, key_handle->cached_key, size); - if (result != OEMCrypto_SUCCESS) { - memset(key_handle->cached_key, 0, sizeof(key_handle->cached_key)); - return result; - } - key_handle->is_key_cached = true; - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle, - KeySize* size) { - if (key_handle == NULL || size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - WTPI_K1_SymmetricKey* key = - OPKI_GetFromObjectTable(&key_table, key_handle->index); - *size = key->key_size; - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult AESCTRDecryptWithKeyHandle( - WTPI_K1_SymmetricKey_Handle key_handle, - const uint8_t* in, - size_t in_length, - const uint8_t* iv, - size_t block_offset, - uint8_t* out) { - if (key_handle == NULL || in == NULL || in_length == 0 || - block_offset >= AES_BLOCK_SIZE || iv == NULL || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - KeySize key_size; - OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(key_handle, (size_t)key_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_AESCTRDecrypt(in, in_length, iv, key_handle->cached_key, - (size_t)key_size, block_offset, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -/****************************************************************************** - The following implement the layer 1 crypto interface. -*******************************************************************************/ - -OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_SymmetricKey_Handle key_handle, - size_t key_length, - const uint8_t* in, - size_t in_length, - const uint8_t* iv, - uint8_t* out) { - if (key_handle == NULL || in == NULL || in_length == 0 || - in_length % AES_BLOCK_SIZE != 0 || iv == NULL || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const KeySize key_size = OPK_LengthToKeySize(key_length); - if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - OEMCryptoResult result = PrepareCachedKey(key_handle, key_length); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_AESCBCDecrypt(in, in_length, iv, key_handle->cached_key, - key_length, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle, - const uint8_t* in, - size_t in_length, - const uint8_t* iv, - uint8_t* out) { - if (key_handle == NULL || in == NULL || in_length == 0 || - in_length % AES_BLOCK_SIZE != 0 || iv == NULL || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - KeySize encryption_key_size; - OEMCryptoResult result = - WTPI_K1_GetKeySize(key_handle, &encryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(key_handle, (size_t)encryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_AESCBCEncrypt(in, in_length, iv, key_handle->cached_key, - (size_t)encryption_key_size, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, - size_t message_length, - uint8_t* out) { - if (message == NULL || message_length == 0 || out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!SHA256(message, message_length, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key_handle, - const uint8_t* message, - size_t message_length, - uint8_t* out) { - if (key_handle == NULL || message == NULL || message_length == 0 || - out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - KeySize hmac_key_size; - OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &hmac_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(key_handle, (size_t)hmac_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_HMAC_SHA1(message, message_length, key_handle->cached_key, - (size_t)hmac_key_size, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle, - const uint8_t* message, - size_t message_length, - uint8_t* out) { - if (key_handle == NULL || message == NULL || message_length == 0 || - out == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - KeySize hmac_key_size; - OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &hmac_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(key_handle, (size_t)hmac_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (!OPKI_HMAC_SHA256(message, message_length, key_handle->cached_key, - (size_t)hmac_key_size, out)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify( - WTPI_K1_SymmetricKey_Handle key_handle, - const uint8_t* message, - size_t message_length, - const uint8_t* signature) { - if (key_handle == NULL || message == NULL || message_length == 0 || - signature == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - uint8_t computed_signature[SHA256_DIGEST_LENGTH]; - OEMCryptoResult result = WTPI_C1_HMAC_SHA256( - key_handle, message, message_length, computed_signature); - if (result != OEMCrypto_SUCCESS) - return result; - if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -/****************************************************************************** - The following implement the layer 1 key management interface. -*******************************************************************************/ - -OEMCryptoResult WTPI_K1_InitializeKeyManagement(void) { - OPKI_UnsafeClearObjectTable(&key_table); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_K1_TerminateKeyManagement(void) { - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_K1_CreateKeyHandle( - const uint8_t* serialized_bytes, - size_t size, - SymmetricKeyType key_type, - WTPI_K1_SymmetricKey_Handle* out_key_handle) { - if (serialized_bytes == NULL || size == 0 || out_key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const KeySize key_size = OPK_LengthToKeySize(size); - if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - uint32_t index; - WTPI_K1_SymmetricKey* key = OPKI_AllocFromObjectTable(&key_table, &index); - if (key == NULL) - return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; - OEMCryptoResult result = EncryptAndSignKey(serialized_bytes, size, - (uint8_t*)(&key->key_data), - sizeof(key->key_data)); - if (result != OEMCrypto_SUCCESS) { - OPKI_FreeFromObjectTable(&key_table, key); - return result; - } - key->key_type = key_type; - key->key_size = key_size; - - WTPI_K1_SymmetricKey_Handle handle = - malloc(sizeof(wtpi_k1_symmetric_key_handle)); - if (handle == NULL) { - OPKI_FreeFromObjectTable(&key_table, key); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - handle->index = index; - handle->is_key_cached = false; - memset(handle->cached_key, 0, sizeof(handle->cached_key)); - *out_key_handle = handle; - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( - uint32_t context, - SymmetricKeyType out_key_type, - WTPI_K1_SymmetricKey_Handle* out_key_handle, - KeySize out_key_size) { - if (out_key_handle == NULL) - return OEMCrypto_ERROR_INVALID_CONTEXT; - uint8_t derived_key[KEY_SIZE_256]; - OEMCryptoResult result = DeriveFromDeviceKey(context, out_key_type, - derived_key, out_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - - return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size, - out_key_type, out_key_handle); -} - -OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle( - WTPI_K1_SymmetricKey_Handle decrypt_key_handle, - const uint8_t* enc_key, - size_t enc_key_length, - const uint8_t* iv, - SymmetricKeyType key_type, - WTPI_K1_SymmetricKey_Handle* out_key_handle) { - if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 || - out_key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(decrypt_key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const KeySize key_size = OPK_LengthToKeySize(enc_key_length); - if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - KeySize decryption_key_size; - OEMCryptoResult result = - WTPI_K1_GetKeySize(decrypt_key_handle, &decryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(decrypt_key_handle, (size_t)decryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - uint8_t key[KEY_SIZE_256]; - if (!OPKI_AESCBCDecrypt(enc_key, enc_key_length, iv, - decrypt_key_handle->cached_key, - (size_t)decryption_key_size, key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (result != OEMCrypto_SUCCESS) - return result; - return WTPI_K1_CreateKeyHandle(key, enc_key_length, key_type, - out_key_handle); -} - -OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( - WTPI_K1_SymmetricKey_Handle decrypt_key_handle, - const uint8_t* enc_mac_keys, - size_t enc_mac_keys_length, - const uint8_t* iv, - WTPI_K1_SymmetricKey_Handle* out_mac_key_server, - WTPI_K1_SymmetricKey_Handle* out_mac_key_client) { - if (decrypt_key_handle == NULL || enc_mac_keys == NULL || - enc_mac_keys_length == 0 || out_mac_key_server == NULL || - out_mac_key_client == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(decrypt_key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (enc_mac_keys_length != 2 * MAC_KEY_SIZE) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - KeySize decryption_key_size; - OEMCryptoResult result = - WTPI_K1_GetKeySize(decrypt_key_handle, &decryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = PrepareCachedKey(decrypt_key_handle, (size_t)decryption_key_size); - if (result != OEMCrypto_SUCCESS) - return result; - - uint8_t mac_keys[2 * MAC_KEY_SIZE]; - if (!OPKI_AESCBCDecrypt(enc_mac_keys, enc_mac_keys_length, iv, - decrypt_key_handle->cached_key, - (size_t)decryption_key_size, mac_keys)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - result = WTPI_K1_CreateKeyHandle(mac_keys, MAC_KEY_SIZE, MAC_KEY_SERVER, - out_mac_key_server); - if (result != OEMCrypto_SUCCESS) - return result; - result = WTPI_K1_CreateKeyHandle(mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE, - MAC_KEY_CLIENT, out_mac_key_client); - return result; -} - -OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( - WTPI_K1_SymmetricKey_Handle key_handle, - uint8_t counter, - const uint8_t* context, - size_t context_length, - SymmetricKeyType out_key_type, - KeySize out_key_size, - WTPI_K1_SymmetricKey_Handle* out_key_handle) { - if (key_handle == NULL || context == NULL || context_length == 0 || - out_key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - SymmetricKeyType key_type; - OEMCryptoResult result = GetKeyType(key_handle, &key_type); - if (result != OEMCrypto_SUCCESS || key_type != DERIVING_KEY) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - KeySize key_size; - result = WTPI_K1_GetKeySize(key_handle, &key_size); - if (result != OEMCrypto_SUCCESS) - return result; - - result = PrepareCachedKey(key_handle, (size_t)key_size); - if (result != OEMCrypto_SUCCESS) - return result; - - uint8_t derived_key[KEY_SIZE_256]; - if (!OPKI_DeriveKeyWithCMAC(key_handle->cached_key, key_size, counter, - context, context_length, out_key_size, - derived_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size, - out_key_type, out_key_handle); -} - -OEMCryptoResult WTPI_K1_WrapKey(uint32_t context, - WTPI_K1_SymmetricKey_Handle key_handle, - SymmetricKeyType key_type, - uint8_t* wrapped_key, - size_t wrapped_key_length) { - if (key_handle == NULL || wrapped_key == NULL || wrapped_key_length == 0) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - KeySize key_size; - OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &key_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (wrapped_key_length < (size_t)key_size) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - result = PrepareCachedKey(key_handle, (size_t)key_size); - if (result != OEMCrypto_SUCCESS) - return result; - - /* TODO(b/158766099): encrypt the data instead of memcpy. */ - memcpy(wrapped_key, key_handle->cached_key, (size_t)key_size); - - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( - uint32_t context, - const uint8_t* wrapped_key, - size_t wrapped_key_length, - SymmetricKeyType key_type, - WTPI_K1_SymmetricKey_Handle* out_key_handle) { - if (wrapped_key == NULL || wrapped_key_length == 0 || - out_key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const KeySize key_size = OPK_LengthToKeySize(wrapped_key_length); - if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - /* TODO(b/158766099): decrypt the key data before creating key handle. */ - - return WTPI_K1_CreateKeyHandle(wrapped_key, wrapped_key_length, key_type, - out_key_handle); -} - -OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) { - if (!IsKeyHandleValid(key_handle)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - OEMCryptoResult result = OEMCrypto_SUCCESS; - result = OPKI_FreeFromObjectTableByIndex(&key_table, key_handle->index); - memset(key_handle->cached_key, 0, sizeof(key_handle->cached_key)); - free(key_handle); - return result; -} - -OEMCryptoResult WTPI_C1_CopyToOutputBuffer( - const uint8_t* in, - size_t size, - const OPK_OutputBuffer* output_buffer, - size_t output_offset) { - size_t total_size; - if (OPK_AddOverflowUX(output_offset, size, &total_size)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (in == NULL || output_buffer == NULL || size == 0 || - total_size > output_buffer->size) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - uint8_t* dest = NULL; - if (output_buffer->type == OPK_SECURE_OUTPUT_BUFFER) { - OEMCryptoResult result = WTPI_GetSecureBufferAddress( - output_buffer->buffer.secure, output_offset, &dest); - if (result != OEMCrypto_SUCCESS) - return result; - } else if (output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { - dest = output_buffer->buffer.clear_insecure + output_offset; - } else { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - memmove(dest, in, size); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { - if (out == NULL || size == 0) - return OEMCrypto_ERROR_INVALID_CONTEXT; - if (RAND_bytes(out, size) != 1) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - return OEMCrypto_SUCCESS; -} diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_asymmetric.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_asymmetric.c deleted file mode 100644 index 2c9ac6e..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_asymmetric.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 2022 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_crypto_asymmetric_interface.h" - -#include -#include -#include -#include - -#include "OEMCryptoCENCCommon.h" -#include "ecc_util.h" -#include "oemcrypto_check_macros.h" -#include "oemcrypto_compiler_attributes.h" -#include "oemcrypto_key_types.h" -#include "openssl/curve25519.h" -#include "openssl/evp.h" -#include "openssl/hkdf.h" -#include "openssl/rsa.h" -#include "openssl/x509.h" -#include "rsa_util.h" -#include "wtpi_abort_interface.h" -#include "wtpi_device_key_access_interface.h" -#include "wtpi_device_key_interface.h" -#include "wtpi_logging_interface.h" - -typedef struct tee_asymmetric_key_handle { - AsymmetricKeyType key_type; - RSA* rsa_key; - EC_KEY* ecc_key; - // Consider to use EVP_KEY instead of serialized key. - uint8_t ed25519_key[ED25519_PRIVATE_KEY_LEN]; -} tee_asymmetric_key_handle; - -// Returns true as long as one byte of ed25519_key is non-zero. -static bool HasED25519Key(WTPI_AsymmetricKey_Handle key_handle) { - for (size_t i = 0; i < ED25519_PRIVATE_KEY_LEN; ++i) { - if (key_handle->ed25519_key[i] != 0) { - return true; - } - } - return false; -} - -static bool IsAsymmetricKeyHandleValid(WTPI_AsymmetricKey_Handle key_handle) { - if (key_handle == NULL) - return false; - switch (key_handle->key_type) { - case DRM_RSA_PRIVATE_KEY: { - if (key_handle->rsa_key == NULL) - return false; - if (key_handle->ecc_key != NULL) - return false; - if (HasED25519Key(key_handle)) - return false; - break; - } - case DRM_ECC_PRIVATE_KEY: { - if (key_handle->ecc_key == NULL) - return false; - if (key_handle->rsa_key != NULL) - return false; - if (HasED25519Key(key_handle)) - return false; - break; - } - case PROV40_ED25519_PRIVATE_KEY: { - if (key_handle->ecc_key != NULL) - return false; - if (key_handle->rsa_key != NULL) - return false; - if (!HasED25519Key(key_handle)) - return false; - break; - } - default: - return false; - } - return true; -} - -static bool IsSupportedAsymmetricKeyType(AsymmetricKeyType key_type) { - return (key_type == DRM_RSA_PRIVATE_KEY || - key_type == DRM_ECC_PRIVATE_KEY || - key_type == PROV40_ED25519_PRIVATE_KEY); -} - -static bool CreateAsymmetricRSAKeyHandle(const uint8_t* serialized_bytes, - size_t size, - WTPI_AsymmetricKey_Handle handle) { - if (serialized_bytes == NULL || size == 0 || handle == NULL) { - return false; - } - RSA* rsa = NULL; - if (!DeserializePKCS8PrivateKey(serialized_bytes, size, &rsa)) { - return false; - } - if (!CheckRSAKey(rsa)) { - RSA_free(rsa); - return false; - } - handle->key_type = DRM_RSA_PRIVATE_KEY; - handle->rsa_key = rsa; - return true; -} - -static bool CreateAsymmetricECCKeyHandle(const uint8_t* serialized_bytes, - size_t size, - WTPI_AsymmetricKey_Handle handle) { - EC_KEY* ecc_key = NULL; - if (!DeserializeECCPrivateKey(serialized_bytes, size, &ecc_key)) { - return false; - } - /* DeserializeECCPrivateKey will check the key after deserializing. */ - handle->key_type = DRM_ECC_PRIVATE_KEY; - handle->ecc_key = ecc_key; - return true; -} - -static bool CreateAsymmetricED25519KeyHandle(const uint8_t* serialized_bytes, - size_t size, - WTPI_AsymmetricKey_Handle handle) { - if (serialized_bytes == NULL || size != ED25519_PRIVATE_KEY_LEN) { - return false; - } - handle->key_type = PROV40_ED25519_PRIVATE_KEY; - memcpy(handle->ed25519_key, serialized_bytes, size); - return true; -} - -OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( - const uint8_t* serialized_bytes, - size_t size, - AsymmetricKeyType key_type, - WTPI_AsymmetricKey_Handle* key_handle) { - if (serialized_bytes == NULL || size == 0 || - !IsSupportedAsymmetricKeyType(key_type) || key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - WTPI_AsymmetricKey_Handle handle = - malloc(sizeof(tee_asymmetric_key_handle)); - if (handle == NULL) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - memset(handle, 0, sizeof(*handle)); - switch (key_type) { - case DRM_RSA_PRIVATE_KEY: { - if (!CreateAsymmetricRSAKeyHandle(serialized_bytes, size, handle)) - goto cleanup; - break; - } - case DRM_ECC_PRIVATE_KEY: { - if (!CreateAsymmetricECCKeyHandle(serialized_bytes, size, handle)) - goto cleanup; - break; - } - case PROV40_ED25519_PRIVATE_KEY: { - if (!CreateAsymmetricED25519KeyHandle(serialized_bytes, size, handle)) - goto cleanup; - break; - } - } - *key_handle = handle; - return OEMCrypto_SUCCESS; -cleanup: - if (handle) { - free(handle); - } - // TODO(b/201581141): Renamed to be more applicable to both RSA and ECC - // keys. - return OEMCrypto_ERROR_INVALID_RSA_KEY; -} - -OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( - WTPI_AsymmetricKey_Handle key_handle) { - if (key_handle == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - switch (key_handle->key_type) { - case DRM_RSA_PRIVATE_KEY: { - RSA_free(key_handle->rsa_key); - key_handle->rsa_key = NULL; - break; - } - case DRM_ECC_PRIVATE_KEY: { - EC_KEY_free(key_handle->ecc_key); - key_handle->ecc_key = NULL; - break; - } - case PROV40_ED25519_PRIVATE_KEY: { - memset(key_handle->ed25519_key, 0, sizeof(key_handle->ed25519_key)); - break; - } - } - free(key_handle); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key_handle, - const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length, - RSA_Padding_Scheme padding_scheme) { - if (key_handle == NULL || message == NULL || message_length == 0 || - signature_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - RSA* rsa = key_handle->rsa_key; - const size_t max_signature_size = (size_t)RSA_size(rsa); - if (signature == NULL || *signature_length < max_signature_size) { - *signature_length = max_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - /* This is the standard padding scheme used for license requests. */ - if (padding_scheme == kSign_RSASSA_PSS) { - size_t local_signature_length = *signature_length; - if (!RSASignSSAPSSSHA1(rsa, message, message_length, signature, - &local_signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - *signature_length = local_signature_length; - /* This is the alternate padding scheme used by cast receivers only. */ - } else if (padding_scheme == kSign_PKCS1_Block1) { - /* Pad the message with PKCS1 padding, and then encrypt. */ - const int encrypt_res = RSA_private_encrypt( - message_length, message, signature, rsa, RSA_PKCS1_PADDING); - if (encrypt_res <= 0) { - dump_ssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - *signature_length = (size_t)encrypt_res; - } else { /* Bad RSA_Padding_Scheme */ - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key_handle, - const uint8_t* in, - size_t in_length, - uint8_t* out, - size_t* out_length) { - if (key_handle == NULL || in == NULL || in_length == 0 || out == NULL || - out_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - RSA* rsa = key_handle->rsa_key; - const size_t max_cleartext_size = (size_t)RSA_size(rsa); - if (*out_length < max_cleartext_size) { - *out_length = max_cleartext_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (!RSAPrivateDecrypt(rsa, in, in_length, out, out_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key_handle, - const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - if (key_handle == NULL || message == NULL || message_length == 0 || - signature_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - EC_KEY* ecc_key = key_handle->ecc_key; - const size_t max_signature_size = ECDSA_size(ecc_key); - if (signature == NULL || *signature_length < max_signature_size) { - *signature_length = max_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (!ECCSignECDSA(ecc_key, message, message_length, signature, - signature_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key_handle, - const uint8_t* key_source, - size_t key_source_length, - uint8_t* session_key, - size_t* session_key_length) { - if (key_handle == NULL || key_source == NULL || key_source_length == 0 || - session_key_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (session_key == NULL || *session_key_length < KEY_SIZE_256) { - *session_key_length = KEY_SIZE_256; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - EC_KEY* ecc_key = key_handle->ecc_key; - if (!ECCWidevineECDHSessionKey(ecc_key, key_source, key_source_length, - session_key, session_key_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key_handle, - size_t* key_size) { - if (key_handle == NULL || key_size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); - *key_size = 0; - switch (key_handle->key_type) { - case DRM_RSA_PRIVATE_KEY: - *key_size = RSA_size(key_handle->rsa_key); - break; - case DRM_ECC_PRIVATE_KEY: - *key_size = ECDSA_size(key_handle->ecc_key); - break; - case PROV40_ED25519_PRIVATE_KEY: - *key_size = ED25519_SIGNATURE_LEN; - break; - } - if (*key_size == 0) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_ED25519Sign(WTPI_AsymmetricKey_Handle key, - const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { - if (out_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (out == NULL || *out_length < HWBCC_MAX_RESP_PAYLOAD_SIZE) { - *out_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - // Call with an all zero key and ignore the signature. - uint8_t key_unused[32]; - memset(key_unused, 0, sizeof(key_unused)); - uint8_t signature_unused[HWBCC_MAX_RESP_PAYLOAD_SIZE]; - size_t signature_size_unused = 0; - int result = hwbcc_get_protected_data( - /*test_mode=*/false, /*cose_algorithm=*/HWBCC_ALGORITHM_ED25519, - /*key=*/key_unused, /*key_size=*/sizeof(key_unused), - /*aad=*/NULL, /*aad_size=*/0, /*cose_sign1=*/signature_unused, - /*cose_sign1_buf_size=*/sizeof(signature_unused), - /*cose_sign1_size=*/&signature_size_unused, /*bcc=*/out, - /*bcc_buf_size=*/*out_length, /*bcc_size=*/out_length); - - return result == 0 ? OEMCrypto_SUCCESS : OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( - AsymmetricKeyType* key_type, - uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length, - uint8_t* public_key, - size_t* public_key_length) { - if (key_type == NULL || wrapped_private_key_length == NULL || - public_key_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // This implementation generates ECC key. An alternative is RSA key. - *key_type = DRM_ECC_PRIVATE_KEY; - // Check buffer sizes. - size_t required_wrapped_private_key_length = 0; - OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( - PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE, *key_type, - &required_wrapped_private_key_length); - if (result != OEMCrypto_SUCCESS) - return result; - const size_t required_public_key_length = PKCS8_ECC_KEY_MAX_SIZE; - if (wrapped_private_key == NULL || - *wrapped_private_key_length < required_wrapped_private_key_length || - public_key == NULL || *public_key_length < required_public_key_length) { - *wrapped_private_key_length = required_wrapped_private_key_length; - *public_key_length = required_public_key_length; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - uint8_t clear_private_key[PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE]; - size_t clear_private_key_length = sizeof(clear_private_key); - if (!NewEccKeyPair(clear_private_key, &clear_private_key_length, public_key, - public_key_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Add padding. - const uint8_t padding = - AES_BLOCK_SIZE - (clear_private_key_length % AES_BLOCK_SIZE); - memset(clear_private_key + clear_private_key_length, padding, padding); - clear_private_key_length += padding; - - size_t actual_wrapped_private_key_length = 0; - result = WTPI_GetWrappedAsymmetricKeySize( - clear_private_key_length, *key_type, - &actual_wrapped_private_key_length); - if (result != OEMCrypto_SUCCESS) - return result; - if (*wrapped_private_key_length < actual_wrapped_private_key_length) { - // This should not happen as we have checked buffer size. - *wrapped_private_key_length = actual_wrapped_private_key_length; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - *wrapped_private_key_length = actual_wrapped_private_key_length; - return WTPI_WrapAsymmetricKey(wrapped_private_key, - *wrapped_private_key_length, *key_type, - clear_private_key, clear_private_key_length); -} - -OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - if (message == NULL || message_length == 0 || signature_length == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // The message is expected to be an EC p256 certificate public key. - // Notice that the signature contains |message| itself. - if (message_length > HWBCC_MAX_ENCODED_KEY_SIZE) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - if (signature == NULL || *signature_length < HWBCC_MAX_RESP_PAYLOAD_SIZE) { - *signature_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - // Ignore the BCC returned. - uint8_t bcc_unused[HWBCC_MAX_RESP_PAYLOAD_SIZE]; - size_t bcc_size_unused = 0; - int result = hwbcc_get_protected_data( - /*test_mode=*/false, /*cose_algorithm=*/HWBCC_ALGORITHM_ED25519, - /*key=*/message, /*key_size=*/message_length, /*aad=*/NULL, - /*aad_size=*/0, /*cose_sign1=*/signature, - /*cose_sign1_buf_size=*/*signature_length, - /*cose_sign1_size=*/signature_length, /*bcc=*/bcc_unused, - /*bcc_buf_size=*/sizeof(bcc_unused), /*bcc_size=*/&bcc_size_unused); - - return result == 0 ? OEMCrypto_SUCCESS : OEMCrypto_ERROR_UNKNOWN_FAILURE; -} diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_device_key.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_device_key.c deleted file mode 100644 index ca50327..0000000 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_device_key.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ -#define TLOG_TAG "DEVICEKEY" - -#include "wtpi_device_key_interface.h" - -#include -#include - -#include "device_key_v0_interface.h" -#include "oemcrypto_key_types.h" -#include "oemcrypto_overflow.h" -#include "wtpi_crypto_and_key_management_interface_layer1.h" - -#define UUID_LENGTH 16 - -// If changing the WrappedData struct family, make sure to update -// ENCRYPT_AND_SIGN_EXTRA in wtpi_config_macros.h if needed. - -// This struct represents a wrapped blob that we do not yet know how to -// interpret. It contains only the fields that we expect every versioned blob to -// have. -typedef struct WrappedData { - uint8_t signature[SHA256_DIGEST_LENGTH]; - uint8_t magic[UUID_LENGTH]; - uint8_t version[sizeof(uint32_t)]; - uint8_t data[]; -} WrappedData; - -// The randomly-generated UUID that identifies a blob as a WrappedData struct, -// in network byte order. -static const uint8_t kMagicUuid[UUID_LENGTH] = { - 0xb5, 0x76, 0x3b, 0xad, 0x84, 0x05, 0x40, 0xfd, - 0xa0, 0x88, 0x3b, 0x6c, 0x69, 0x97, 0xfc, 0x74}; - -// 1 in network byte order -static const uint8_t kVersionOne[sizeof(uint32_t)] = {0x00, 0x00, 0x00, 0x01}; - -// This is the layout of the |data| field of a WrappedData structure when its -// |version| field is 1. -typedef struct WrappedData_V1 { - uint8_t iv[KEY_IV_SIZE]; - uint8_t enc_data[]; -} WrappedData_V1; - -OEMCryptoResult WTPI_GetEncryptAndSignSize(UNUSED uint32_t context, - size_t in_size, - size_t* wrapped_size) { - if (OPK_AddOverflowUX(in_size, sizeof(WrappedData) + sizeof(WrappedData_V1), - wrapped_size)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult WTPI_EncryptAndSign(uint32_t context, - const uint8_t* data, - size_t data_size, - uint8_t* out, - size_t* out_size) { - if (!out_size) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - size_t needed_size; - OEMCryptoResult result = - WTPI_GetEncryptAndSignSize(context, data_size, &needed_size); - if (result != OEMCrypto_SUCCESS) - return result; - if (*out_size < needed_size) { - *out_size = needed_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - // Allow querying size without these buffers. - if (!data || !out) - return OEMCrypto_ERROR_INVALID_CONTEXT; - *out_size = needed_size; - - WrappedData* const wrapped_header = (WrappedData*)out; - memcpy(wrapped_header->magic, kMagicUuid, sizeof(wrapped_header->magic)); - memcpy(wrapped_header->version, kVersionOne, - sizeof(wrapped_header->version)); - - WrappedData_V1* const wrapped_data = (WrappedData_V1*)wrapped_header->data; - /* Pick a random IV for generating keys. */ - result = WTPI_C1_RandomBytes(wrapped_data->iv, sizeof(wrapped_data->iv)); - if (result != OEMCrypto_SUCCESS) - return result; - - // Encrypt the buffer. - WTPI_K1_SymmetricKey_Handle encryption_key = NULL; - result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, ENCRYPTION_KEY, - &encryption_key, KEY_SIZE_128); - if (result != OEMCrypto_SUCCESS) - return result; - result = WTPI_C1_AESCBCEncrypt(encryption_key, data, data_size, - wrapped_data->iv, wrapped_data->enc_data); - WTPI_K1_FreeKeyHandle(encryption_key); - if (result != OEMCrypto_SUCCESS) - return result; - - // Compute the signature of the data past the signature block and store it - // at the start of the output buffer. - WTPI_K1_SymmetricKey_Handle signing_key = NULL; - result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, MAC_KEY_CLIENT, - &signing_key, KEY_SIZE_256); - if (result != OEMCrypto_SUCCESS) - return result; - const size_t offset = sizeof(wrapped_header->signature); - result = - WTPI_C1_HMAC_SHA256(signing_key, out + offset, needed_size - offset, - wrapped_header->signature); - WTPI_K1_FreeKeyHandle(signing_key); - return result; -} - -static OEMCryptoResult VerifyAndDecrypt_V1(uint32_t context, - const uint8_t* data, - size_t data_size, - uint8_t* out, - size_t* out_size) { - // We explicitly defer checking |out| until later, to allow querying the - // size without an out buffer. - if (data == NULL || - data_size < sizeof(WrappedData) + sizeof(WrappedData_V1) || - out_size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - const WrappedData* const wrapped_header = (const WrappedData*)data; - - // Verify the signature first, before interpreting. - WTPI_K1_SymmetricKey_Handle signing_key = NULL; - OEMCryptoResult result = WTPI_K1_DeriveDeviceKeyIntoHandle( - context, MAC_KEY_SERVER, &signing_key, KEY_SIZE_256); - if (result != OEMCrypto_SUCCESS) - return result; - const size_t offset = sizeof(wrapped_header->signature); - result = WTPI_C1_HMAC_SHA256_Verify(signing_key, data + offset, - data_size - offset, - wrapped_header->signature); - WTPI_K1_FreeKeyHandle(signing_key); - if (result != OEMCrypto_SUCCESS) - return result; - - // If someday we support multiple versions, we'll need to decode - // wrapped_header->version and switch our behavior depending on the version - // we find. But for now, since only version 1 is valid, we can just verify - // that wrapped_header->version is 1. - if (memcmp(wrapped_header->magic, kMagicUuid, - sizeof(wrapped_header->magic)) != 0 || - memcmp(wrapped_header->version, kVersionOne, - sizeof(wrapped_header->version)) != 0) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - const size_t needed_size = - data_size - (sizeof(WrappedData) + sizeof(WrappedData_V1)); - if (*out_size < needed_size) { - *out_size = needed_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - // We defer this check to allow querying the size without an out buffer. - if (out == NULL) - return OEMCrypto_ERROR_INVALID_CONTEXT; - *out_size = needed_size; - - const WrappedData_V1* const wrapped_data = - (const WrappedData_V1*)wrapped_header->data; - - // Decrypt the buffer. - WTPI_K1_SymmetricKey_Handle encryption_key = NULL; - result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, ENCRYPTION_KEY, - &encryption_key, KEY_SIZE_128); - if (result != OEMCrypto_SUCCESS) - return result; - KeySize key_size; - result = WTPI_K1_GetKeySize(encryption_key, &key_size); - if (result != OEMCrypto_SUCCESS) - return result; - result = WTPI_C1_AESCBCDecrypt(encryption_key, (size_t)key_size, - wrapped_data->enc_data, needed_size, - wrapped_data->iv, out); - WTPI_K1_FreeKeyHandle(encryption_key); - return result; -} - -// The input |data| buffer can be either a serialized WrappedData blob, or a -// wrapped RSA key in old format used on Pixel 6 devices that are already in the -// fields. The implementation of this function needs to detect and handle the -// old format wrapped key to provide backwards-compatibility. -OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, - const uint8_t* data, - size_t data_size, - uint8_t* out, - size_t* out_size) { - if (data == NULL || data_size == 0 || out == NULL || out_size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // Handle the wrapped RSA key in old format - bool is_v0_drm_key_candidate = false; - if (data_size < sizeof(WrappedData)) { - is_v0_drm_key_candidate = true; - } else { - const WrappedData* wrapped_header = (WrappedData*)data; - if (memcmp(wrapped_header->magic, kMagicUuid, UUID_LENGTH) != 0) { - is_v0_drm_key_candidate = true; - } - } - if (is_v0_drm_key_candidate) { - if (context != DEVICE_KEY_WRAP_DRM_CERT) { - TLOGE("Either the format of the wrapped data is unrecognized, or" - "the context value is invalid. context = %u", - context); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - TLOGD("DRM key wrapped in legacy format detected."); - return VerifyAndDecryptDRMKeyData_V0(data, data_size, out); - } - // Handle other versioned WrappedData blob - // This function is broken out separately in order to ease maintenance for - // those who also need to maintain backwards-compatibility with other - // versioned wrapping formats. - return VerifyAndDecrypt_V1(context, data, data_size, out, out_size); -} - -// The input |wrapped| buffer can be either an encrypted usage table header -// blob, or an encrypted usage entry blob. This function shall only be called on -// a Pixel 6 device in the field which has usage table and entry data wrapped in -// an old format. -OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy(const uint8_t* wrapped, - size_t wrapped_size, - const uint8_t* signature, - const uint8_t* iv, - uint8_t* out) { - return VerifyAndDecryptUsageData_V0(wrapped, wrapped_size, signature, iv, - out); -} \ No newline at end of file diff --git a/oemcrypto/opk/ports/trusty/ta/reference/include/opk_config.h b/oemcrypto/opk/ports/trusty/ta/reference/include/opk_config.h new file mode 100644 index 0000000..cd25c62 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/include/opk_config.h @@ -0,0 +1,35 @@ + +/* + * Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef _OPK_CONFIG_H_ +#define _OPK_CONFIG_H_ + +#ifndef OPK_CONFIG_RESOURCE_RATING_TIER +# define OPK_CONFIG_RESOURCE_RATING_TIER 3 +#endif + +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO +# define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO 500 * 1024 +#endif + +#ifndef OPK_CONFIG_MAX_SAMPLE_SIZE +# 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 + +#ifndef MAX_NUMBER_OF_ASYMMETRIC_KEYS +# define MAX_NUMBER_OF_ASYMMETRIC_KEYS 8 +#endif + +// Use defaults from wtpi_reference for the rest +#include "config/default.h" + +#endif diff --git a/oemcrypto/opk/ports/trusty/ta/include/system_specific.h b/oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/include/system_specific.h rename to oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h diff --git a/oemcrypto/opk/ports/trusty/ta/include/tee_context.h b/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h similarity index 89% rename from oemcrypto/opk/ports/trusty/ta/include/tee_context.h rename to oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h index fcb615b..0ee246d 100644 --- a/oemcrypto/opk/ports/trusty/ta/include/tee_context.h +++ b/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h @@ -20,7 +20,8 @@ typedef struct tee_context { storage_session_t user_data_session; - storage_session_t provisioning_session; + storage_session_t old_provisioning_session; + storage_session_t new_provisioning_session; } tee_context; tee_context* get_tee_context(); diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/transport_interface.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/transport_interface.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/transport_interface.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/transport_interface.c diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_clock_layer2.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_clock_layer2.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_clock_layer2.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_clock_layer2.c diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c new file mode 100644 index 0000000..dd0afc9 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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 + +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; +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_crypto_asymmetric.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_crypto_asymmetric.c new file mode 100644 index 0000000..b274cd4 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_crypto_asymmetric.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2022 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_crypto_asymmetric_interface.h" + +#include +#include +#include + +#include "OEMCryptoCENCCommon.h" +#include "ecc_util.h" +#include "oemcrypto_check_macros.h" +#include "oemcrypto_compiler_attributes.h" +#include "oemcrypto_key_types.h" +#include "openssl/curve25519.h" +#include "openssl/evp.h" +#include "openssl/hkdf.h" +#include "openssl/rsa.h" +#include "openssl/x509.h" +#include "rsa_util.h" +#include "wtpi_abort_interface.h" +#include "wtpi_device_key_access_interface.h" +#include "wtpi_device_key_interface.h" +#include "wtpi_logging_interface.h" + +typedef struct tee_asymmetric_key_handle { + AsymmetricKeyType key_type; + RSA* rsa_key; + EC_KEY* ecc_key; + // Consider to use EVP_KEY instead of serialized key. + uint8_t ed25519_key[ED25519_PRIVATE_KEY_LEN]; +} tee_asymmetric_key_handle; + +// Returns true as long as one byte of ed25519_key is non-zero. +static bool HasED25519Key(WTPI_AsymmetricKey_Handle key_handle) { + for (size_t i = 0; i < ED25519_PRIVATE_KEY_LEN; ++i) { + if (key_handle->ed25519_key[i] != 0) { + return true; + } + } + return false; +} + +static bool IsAsymmetricKeyHandleValid(WTPI_AsymmetricKey_Handle key_handle) { + if (key_handle == NULL) return false; + switch (key_handle->key_type) { + case DRM_RSA_PRIVATE_KEY: { + if (key_handle->rsa_key == NULL) return false; + if (key_handle->ecc_key != NULL) return false; + if (HasED25519Key(key_handle)) return false; + break; + } + case DRM_ECC_PRIVATE_KEY: { + if (key_handle->ecc_key == NULL) return false; + if (key_handle->rsa_key != NULL) return false; + if (HasED25519Key(key_handle)) return false; + break; + } + case PROV40_ED25519_PRIVATE_KEY: { + if (key_handle->ecc_key != NULL) return false; + if (key_handle->rsa_key != NULL) return false; + if (!HasED25519Key(key_handle)) return false; + break; + } + default: + return false; + } + return true; +} + +static bool IsSupportedAsymmetricKeyType(AsymmetricKeyType key_type) { + return (key_type == DRM_RSA_PRIVATE_KEY || key_type == DRM_ECC_PRIVATE_KEY || + key_type == PROV40_ED25519_PRIVATE_KEY); +} + +static bool CreateAsymmetricRSAKeyHandle(const uint8_t* serialized_bytes, + size_t size, + WTPI_AsymmetricKey_Handle handle) { + if (serialized_bytes == NULL || size == 0 || handle == NULL) { + return false; + } + RSA* rsa = NULL; + if (!DeserializePKCS8PrivateKey(serialized_bytes, size, &rsa)) { + return false; + } + if (!CheckRSAKey(rsa)) { + RSA_free(rsa); + return false; + } + handle->key_type = DRM_RSA_PRIVATE_KEY; + handle->rsa_key = rsa; + return true; +} + +static bool CreateAsymmetricECCKeyHandle(const uint8_t* serialized_bytes, + size_t size, + WTPI_AsymmetricKey_Handle handle) { + EC_KEY* ecc_key = NULL; + if (!DeserializeECCPrivateKey(serialized_bytes, size, &ecc_key)) { + return false; + } + /* DeserializeECCPrivateKey will check the key after deserializing. */ + handle->key_type = DRM_ECC_PRIVATE_KEY; + handle->ecc_key = ecc_key; + return true; +} + +static bool CreateAsymmetricED25519KeyHandle(const uint8_t* serialized_bytes, + size_t size, + WTPI_AsymmetricKey_Handle handle) { + if (serialized_bytes == NULL || size != ED25519_PRIVATE_KEY_LEN) { + return false; + } + handle->key_type = PROV40_ED25519_PRIVATE_KEY; + memcpy(handle->ed25519_key, serialized_bytes, size); + return true; +} + +OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( + const uint8_t* serialized_bytes, size_t size, AsymmetricKeyType key_type, + WTPI_AsymmetricKey_Handle* key_handle) { + if (serialized_bytes == NULL || size == 0 || + !IsSupportedAsymmetricKeyType(key_type) || key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + WTPI_AsymmetricKey_Handle handle = malloc(sizeof(tee_asymmetric_key_handle)); + if (handle == NULL) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(handle, 0, sizeof(*handle)); + switch (key_type) { + case DRM_RSA_PRIVATE_KEY: { + if (!CreateAsymmetricRSAKeyHandle(serialized_bytes, size, handle)) + goto cleanup; + break; + } + case DRM_ECC_PRIVATE_KEY: { + if (!CreateAsymmetricECCKeyHandle(serialized_bytes, size, handle)) + goto cleanup; + break; + } + case PROV40_ED25519_PRIVATE_KEY: { + if (!CreateAsymmetricED25519KeyHandle(serialized_bytes, size, handle)) + goto cleanup; + break; + } + } + *key_handle = handle; + return OEMCrypto_SUCCESS; +cleanup: + if (handle) { + free(handle); + } + // TODO(b/201581141): Renamed to be more applicable to both RSA and ECC + // keys. + return OEMCrypto_ERROR_INVALID_RSA_KEY; +} + +OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( + WTPI_AsymmetricKey_Handle key_handle) { + if (key_handle == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + switch (key_handle->key_type) { + case DRM_RSA_PRIVATE_KEY: { + RSA_free(key_handle->rsa_key); + key_handle->rsa_key = NULL; + break; + } + case DRM_ECC_PRIVATE_KEY: { + EC_KEY_free(key_handle->ecc_key); + key_handle->ecc_key = NULL; + break; + } + case PROV40_ED25519_PRIVATE_KEY: { + memset(key_handle->ed25519_key, 0, sizeof(key_handle->ed25519_key)); + break; + } + } + free(key_handle); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key_handle, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length, + RSA_Padding_Scheme padding_scheme) { + if (key_handle == NULL || message == NULL || message_length == 0 || + signature_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + RSA* rsa = key_handle->rsa_key; + const size_t max_signature_size = (size_t)RSA_size(rsa); + if (signature == NULL || *signature_length < max_signature_size) { + *signature_length = max_signature_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + /* This is the standard padding scheme used for license requests. */ + if (padding_scheme == kSign_RSASSA_PSS) { + size_t local_signature_length = *signature_length; + if (!RSASignSSAPSSSHA256(rsa, message, message_length, signature, + &local_signature_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *signature_length = local_signature_length; + /* This is the alternate padding scheme used by cast receivers only. */ + } else if (padding_scheme == kSign_PKCS1_Block1) { + /* Pad the message with PKCS1 padding, and then encrypt. */ + const int encrypt_res = RSA_private_encrypt( + message_length, message, signature, rsa, RSA_PKCS1_PADDING); + if (encrypt_res <= 0) { + dump_ssl_error(); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *signature_length = (size_t)encrypt_res; + } else { /* Bad RSA_Padding_Scheme */ + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key_handle, + const uint8_t* in, size_t in_length, + uint8_t* out, size_t* out_length) { + if (key_handle == NULL || in == NULL || in_length == 0 || out == NULL || + out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + RSA* rsa = key_handle->rsa_key; + const size_t max_cleartext_size = (size_t)RSA_size(rsa); + if (*out_length < max_cleartext_size) { + *out_length = max_cleartext_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (!RSAPrivateDecrypt(rsa, in, in_length, out, out_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key_handle, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length) { + if (key_handle == NULL || message == NULL || message_length == 0 || + signature_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + EC_KEY* ecc_key = key_handle->ecc_key; + const size_t max_signature_size = ECDSA_size(ecc_key); + if (signature == NULL || *signature_length < max_signature_size) { + *signature_length = max_signature_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + if (!ECCSignECDSA(ecc_key, message, message_length, signature, + signature_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key_handle, + const uint8_t* key_source, + size_t key_source_length, + uint8_t* session_key, + size_t* session_key_length) { + if (key_handle == NULL || key_source == NULL || key_source_length == 0 || + session_key_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key == NULL || *session_key_length < KEY_SIZE_256) { + *session_key_length = KEY_SIZE_256; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + EC_KEY* ecc_key = key_handle->ecc_key; + if (!ECCWidevineECDHSessionKey(ecc_key, key_source, key_source_length, + session_key, session_key_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key_handle, + size_t* key_size) { + if (key_handle == NULL || key_size == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle."); + *key_size = 0; + switch (key_handle->key_type) { + case DRM_RSA_PRIVATE_KEY: + *key_size = RSA_size(key_handle->rsa_key); + break; + case DRM_ECC_PRIVATE_KEY: + *key_size = ECDSA_size(key_handle->ecc_key); + break; + case PROV40_ED25519_PRIVATE_KEY: + *key_size = ED25519_SIGNATURE_LEN; + break; + } + if (*key_size == 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetSignatureHashAlgorithm( + WTPI_AsymmetricKey_Handle key, AsymmetricKeyType key_type, + OEMCrypto_SignatureHashAlgorithm* hash_algorithm) { + RETURN_INVALID_CONTEXT_IF_NULL(key); + RETURN_INVALID_CONTEXT_IF_NULL(hash_algorithm); + ABORT_IF(!IsAsymmetricKeyHandleValid(key), "Impossible key handle."); + if (key_type != key->key_type) { + LOGE("Passed-in key's type does not match passed-in key type."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + switch (key_type) { + case DRM_RSA_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA2_256; + return OEMCrypto_SUCCESS; + + case DRM_ECC_PRIVATE_KEY: + if (GetECCKeyECDSAHashAlgorithm(key->ecc_key, hash_algorithm)) { + return OEMCrypto_SUCCESS; + } else { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + case PROV40_ED25519_PRIVATE_KEY: + *hash_algorithm = OEMCrypto_SHA2_512; + return OEMCrypto_SUCCESS; + } + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +OEMCryptoResult WTPI_ED25519Sign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_initialize_terminate.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_initialize_terminate.c similarity index 63% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_initialize_terminate.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_initialize_terminate.c index 1c31565..64ad3ed 100644 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_initialize_terminate.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_initialize_terminate.c @@ -26,9 +26,13 @@ #include "tee_context.h" static void close_storage_sessions(tee_context* ctx) { - if (ctx->provisioning_session != STORAGE_INVALID_SESSION) { - storage_close_session(ctx->provisioning_session); - ctx->provisioning_session = STORAGE_INVALID_SESSION; + if (ctx->old_provisioning_session != STORAGE_INVALID_SESSION) { + storage_close_session(ctx->old_provisioning_session); + ctx->old_provisioning_session = STORAGE_INVALID_SESSION; + } + if (ctx->new_provisioning_session != STORAGE_INVALID_SESSION) { + storage_close_session(ctx->new_provisioning_session); + ctx->new_provisioning_session = STORAGE_INVALID_SESSION; } if (ctx->user_data_session != STORAGE_INVALID_SESSION) { storage_close_session(ctx->user_data_session); @@ -41,16 +45,18 @@ OEMCryptoResult WTPI_Initialize(void) { tee_context* ctx = get_tee_context(); - assert(ctx->provisioning_session == STORAGE_INVALID_SESSION); + assert(ctx->old_provisioning_session == STORAGE_INVALID_SESSION); + assert(ctx->new_provisioning_session == STORAGE_INVALID_SESSION); assert(ctx->user_data_session == STORAGE_INVALID_SESSION); storage_session_t newsession; - int rc = storage_open_session(&newsession, STORAGE_CLIENT_TDP_PORT); + int rc = storage_open_session(&newsession, STORAGE_CLIENT_TP_PORT); if (rc < 0) { - TLOGE("WTPI_Initialize: couldn't open provisioning storage session\n"); + TLOGE("WTPI_Initialize: couldn't open provisioning override storage session\n"); + close_storage_sessions(ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - ctx->provisioning_session = newsession; + ctx->new_provisioning_session = newsession; rc = storage_open_session(&newsession, STORAGE_CLIENT_TD_PORT); if (rc < 0) { @@ -59,6 +65,18 @@ OEMCryptoResult WTPI_Initialize(void) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } ctx->user_data_session = newsession; + + rc = storage_open_session(&newsession, STORAGE_CLIENT_TDP_PORT); + if (rc < 0) { + TLOGE("WTPI_Initialize: couldn't open provisioning storage session\n"); + /* + * Don't return an error. We use the new_provisioning_session (TP) + * by default, so we might not need old_provisioning_session (TDP). + */ + } else { + ctx->old_provisioning_session = newsession; + } + return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_persistent_storage.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_persistent_storage.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage.c 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 new file mode 100644 index 0000000..122a20c --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_provisioning_4.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2022 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. + */ + +#define TLOG_TAG "PROV4" + +#include "wtpi_provisioning_4_interface.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "OEMCryptoCENCCommon.h" +#include "cose_util.h" +#include "ecc_util.h" +#include "oemcrypto_check_macros.h" +#include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_logging_interface.h" + +#define MAX_DEVICE_INFO_SIZE 768 + +OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (out == NULL || *out_length < HWBCC_MAX_RESP_PAYLOAD_SIZE) { + *out_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + // Call with an all zero key and ignore the signature. + uint8_t key_unused[32]; + memset(key_unused, 0, sizeof(key_unused)); + uint8_t signature_unused[HWBCC_MAX_RESP_PAYLOAD_SIZE]; + size_t signature_size_unused = 0; + int result = hwbcc_get_protected_data( + /*test_mode=*/false, /*cose_algorithm=*/HWBCC_ALGORITHM_ED25519, + /*key=*/key_unused, /*key_size=*/sizeof(key_unused), + /*aad=*/NULL, /*aad_size=*/0, /*cose_sign1=*/signature_unused, + /*cose_sign1_buf_size=*/sizeof(signature_unused), + /*cose_sign1_size=*/&signature_size_unused, /*bcc=*/out, + /*bcc_buf_size=*/*out_length, /*bcc_size=*/out_length); + + return result == 0 ? OEMCrypto_SUCCESS : OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( + AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length, uint8_t* public_key, + size_t* public_key_length) { + if (key_type == NULL || wrapped_private_key_length == NULL || + public_key_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // This implementation generates ECC key. An alternative is RSA key. + *key_type = DRM_ECC_PRIVATE_KEY; + // Check buffer sizes. + size_t required_wrapped_private_key_length = 0; + OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( + PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE, *key_type, + &required_wrapped_private_key_length); + if (result != OEMCrypto_SUCCESS) return result; + const size_t required_public_key_length = PKCS8_ECC_KEY_MAX_SIZE; + if (wrapped_private_key == NULL || + *wrapped_private_key_length < required_wrapped_private_key_length || + public_key == NULL || *public_key_length < required_public_key_length) { + *wrapped_private_key_length = required_wrapped_private_key_length; + *public_key_length = required_public_key_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + uint8_t clear_private_key[PKCS8_ECC_KEY_MAX_SIZE + AES_BLOCK_SIZE]; + size_t clear_private_key_length = sizeof(clear_private_key); + if (!NewEccKeyPair(clear_private_key, &clear_private_key_length, public_key, + public_key_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Add padding. + const uint8_t padding = + AES_BLOCK_SIZE - (clear_private_key_length % AES_BLOCK_SIZE); + memset(clear_private_key + clear_private_key_length, padding, padding); + clear_private_key_length += padding; + + size_t actual_wrapped_private_key_length = 0; + result = WTPI_GetWrappedAsymmetricKeySize(clear_private_key_length, *key_type, + &actual_wrapped_private_key_length); + if (result != OEMCrypto_SUCCESS) return result; + if (*wrapped_private_key_length < actual_wrapped_private_key_length) { + // This should not happen as we have checked buffer size. + *wrapped_private_key_length = actual_wrapped_private_key_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + *wrapped_private_key_length = actual_wrapped_private_key_length; + return WTPI_WrapAsymmetricKey(wrapped_private_key, + *wrapped_private_key_length, *key_type, + clear_private_key, clear_private_key_length); +} + +OEMCryptoResult WTPI_BccKeyCoseSign1(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) { + if (message == NULL || message_length == 0 || signature_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // The message is expected to be an EC p256 certificate public key. + // Notice that the signature contains |message| itself. + if (message_length > HWBCC_MAX_ENCODED_KEY_SIZE) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + if (signature == NULL || *signature_length < HWBCC_MAX_RESP_PAYLOAD_SIZE) { + *signature_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + // Ignore the BCC returned. + uint8_t bcc_unused[HWBCC_MAX_RESP_PAYLOAD_SIZE]; + size_t bcc_size_unused = 0; + int result = hwbcc_get_protected_data( + /*test_mode=*/false, /*cose_algorithm=*/HWBCC_ALGORITHM_ED25519, + /*key=*/message, /*key_size=*/message_length, /*aad=*/NULL, + /*aad_size=*/0, /*cose_sign1=*/signature, + /*cose_sign1_buf_size=*/*signature_length, + /*cose_sign1_size=*/signature_length, /*bcc=*/bcc_unused, + /*bcc_buf_size=*/sizeof(bcc_unused), /*bcc_size=*/&bcc_size_unused); + + return result == 0 ? OEMCrypto_SUCCESS : OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +OEMCryptoResult WTPI_GetMaxBccKeyCoseSign1Size(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + return OEMCrypto_SUCCESS; +} + +size_t WTPI_MaxDeviceInfoSize(void) { return MAX_DEVICE_INFO_SIZE; } + +OEMCryptoResult WTPI_GetDeviceInformation(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + size_t max_device_info_size = WTPI_MaxDeviceInfoSize(); + if (out == NULL || *out_length < max_device_info_size) { + *out_length = max_device_info_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *out_length = max_device_info_size; + + uint8_t* device_info_buf = NULL; + uint32_t device_info_buf_len = 0; + long rc = keymaster_open(); + if (rc < 0) { + TLOGE("Failed to connect to keymaster (err=%ld)\n", rc); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + OEMCryptoResult result = OEMCrypto_SUCCESS; + keymaster_session_t session = (keymaster_session_t)rc; + rc = keymaster_get_device_info(session, &device_info_buf, + &device_info_buf_len); + if (rc < 0) { + TLOGE("Failed to get device info from keymaster (err=%ld)\n", rc); + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + if (device_info_buf_len == 0) { + TLOGE("Device info is empty\n"); + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + // A validity check on the device info CBOR map + struct CborIn cbor_in; + CborInInit(device_info_buf, device_info_buf_len, &cbor_in); + size_t num_pairs; + if (CborReadMap(&cbor_in, &num_pairs) != CBOR_READ_RESULT_OK) { + TLOGE("Device info byte stream is not valid CBOR or a map\n"); + result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } + TLOGD("Read device info properties count = %zu, total size = %u\n", num_pairs, + device_info_buf_len); + *out_length = device_info_buf_len; + memcpy(out, device_info_buf, *out_length); + result = OEMCrypto_SUCCESS; +cleanup: + free(device_info_buf); + keymaster_close(session); + return result; +} + +OEMCryptoResult WTPI_GetSignedCsrPayload(const uint8_t* challenge, + size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_length) { + if (challenge == NULL || challenge_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encoded_device_info == NULL || encoded_device_info_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (signed_csr_payload_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (signed_csr_payload == NULL || + *signed_csr_payload_length < HWBCC_MAX_RESP_PAYLOAD_SIZE) { + *signed_csr_payload_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *signed_csr_payload_length = HWBCC_MAX_RESP_PAYLOAD_SIZE; + + /* Generate Csr payload to be signed. HWBCC_MAX_RESP_PAYLOAD_SIZE is + * guaranteed to be large enough to hold the Csr payload. */ + uint8_t csr_payload_to_sign[HWBCC_MAX_RESP_PAYLOAD_SIZE]; + size_t csr_payload_to_sign_length = sizeof(csr_payload_to_sign); + OEMCryptoResult result = + GenerateCsrPayload(challenge, challenge_length, encoded_device_info, + encoded_device_info_length, csr_payload_to_sign, + &csr_payload_to_sign_length); + if (result != OEMCrypto_SUCCESS) { + return result; + } + + /* Sign Csr payload. */ + result = WTPI_BccKeyCoseSign1(csr_payload_to_sign, csr_payload_to_sign_length, + signed_csr_payload, signed_csr_payload_length); + return result; +} + +OEMCryptoResult WTPI_GetDeviceFusedStatus(bool* is_fused) { + if (!is_fused) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *is_fused = false; + uint8_t device_info[MAX_DEVICE_INFO_SIZE] = {0}; + size_t device_info_size = MAX_DEVICE_INFO_SIZE; + OEMCryptoResult result = + WTPI_GetDeviceInformation(device_info, &device_info_size); + if (result != OEMCrypto_SUCCESS) { + return result; + } + struct CborIn in; + size_t item_count; + CborInInit(device_info, device_info_size, &in); + if (CborReadMap(&in, &item_count) != CBOR_READ_RESULT_OK) { + TLOGE("device_info is not a valid CBOR map.\n"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const char* kFused = "fused"; + for (size_t i = 0; i < item_count; ++i) { + const char* raw_key; + size_t key_size = 0; + if (CborReadTstr(&in, &key_size, &raw_key) != CBOR_READ_RESULT_OK) { + TLOGE("Failed to read key from device_info map at index: %zu\n", i); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Null-terminating string to hold |raw_key| + char key[64] = {0}; + if (key_size > sizeof(key) - 1) { + TLOGE("Device info map key size too large: %zu", key_size); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memcpy(key, raw_key, key_size); + if (strcmp(key, kFused) == 0) { + int64_t fused = 0; + if (CborReadInt(&in, &fused) != CBOR_READ_RESULT_OK) { + TLOGE("Failed to read %s value from device_info map\n", kFused); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (fused == 1) { + *is_fused = true; + } + break; + } + } + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_root_of_trust_layer2.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c similarity index 78% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_root_of_trust_layer2.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c index b8bad5b..fa13341 100644 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_root_of_trust_layer2.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,7 @@ OEMCryptoResult WTPI_UnwrapRootOfTrust(const uint8_t* input, OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* keybox, size_t length) { TLOGD("WTPI_SaveRootOfTrust\n"); tee_context* ctx = get_tee_context(); - assert(ctx->provisioning_session != STORAGE_INVALID_SESSION); + assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); if (!system_state_provisioning_allowed()) { TLOGE("provisioning not allowed\n"); @@ -85,7 +86,7 @@ OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* keybox, size_t length) { file_handle_t handle; int rc = storage_open_file( - ctx->provisioning_session, &handle, kKeyboxPath, + 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); @@ -104,7 +105,7 @@ OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* keybox, size_t length) { OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* keybox, size_t* length) { TLOGD("WTPI_LoadRootOfTrust\n"); tee_context* ctx = get_tee_context(); - assert(ctx->provisioning_session != STORAGE_INVALID_SESSION); + assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); if (keybox == NULL || length == NULL) { TLOGE("WTPI_LoadRootOfTrust: invalid parameters\n"); @@ -112,11 +113,20 @@ OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* keybox, size_t* length) { } file_handle_t handle; - int rc = storage_open_file(ctx->provisioning_session, &handle, kKeyboxPath, - 0, 0); + 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; } storage_off_t keysize; @@ -143,6 +153,16 @@ OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* keybox, size_t* length) { } 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; } diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_secure_buffer_access.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_secure_buffer_access.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_secure_buffer_access.c rename to oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_secure_buffer_access.c diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/.gitignore b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/.gitignore similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/.gitignore rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/.gitignore diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/Android.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Android.mk similarity index 97% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/Android.mk rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Android.mk index 2ed63b5..3b53f35 100644 --- a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/Android.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Android.mk @@ -1,7 +1,7 @@ # Unified binary LOCAL_PATH:= $(call my-dir) SHARED_DIR := $(LOCAL_PATH)/../shared -CDM_DIR := $(LOCAL_PATH)/../../../../../../ +CDM_DIR := $(LOCAL_PATH)/../../../../../../../ SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/Application.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/Application.mk rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/README.md b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/README.md similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/README.md rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/README.md diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/build.sh b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/build.sh rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/clean.sh b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/clean.sh similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/clean.sh rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/clean.sh diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/include/linux/dma-heap.h b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/include/linux/dma-heap.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/include/linux/dma-heap.h rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/include/linux/dma-heap.h diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/include/trusty_log.h b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/include/trusty_log.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/include/trusty_log.h rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/include/trusty_log.h diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/liboemcrypto-inc.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/liboemcrypto-inc.mk rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/include/trusty/ipc.h b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/include/trusty/ipc.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/include/trusty/ipc.h rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/include/trusty/ipc.h diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/include/trusty/tipc.h b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/include/trusty/tipc.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/include/trusty/tipc.h rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/include/trusty/tipc.h diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/trusty.c b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/trusty.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/libtrusty/trusty.c rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/libtrusty/trusty.c diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/push.sh b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/push.sh similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/push.sh rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/push.sh diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/secure_buffer.c b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/secure_buffer.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/secure_buffer.c rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/secure_buffer.c diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/secure_buffer.h b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/secure_buffer.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/secure_buffer.h rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/secure_buffer.h diff --git a/oemcrypto/opk/ports/trusty/ta/liboemcrypto/transport.c b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/transport.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/liboemcrypto/transport.c rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/transport.c diff --git a/oemcrypto/opk/ports/trusty/ta/manifest.json b/oemcrypto/opk/ports/trusty/ta/reference/manifest.json similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/manifest.json rename to oemcrypto/opk/ports/trusty/ta/reference/manifest.json diff --git a/oemcrypto/opk/ports/trusty/ta/reference/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/rules.mk new file mode 100644 index 0000000..eea7380 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/rules.mk @@ -0,0 +1,141 @@ +# 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 := widevine_reference + +MANIFEST := $(LOCAL_DIR)/manifest.json + +REF_DIR := $(LOCAL_DIR) +PLATFORM_SPECIFIC_DIR := $(LOCAL_DIR) + +SHARED_DIR := $(REF_DIR)/shared +REF_IMPL_DIR := $(REF_DIR)/interface_impls +PLAT_IMPL_DIR := $(PLATFORM_SPECIFIC_DIR)/interface_impls +CDM_DIR ?= ../../../../../../ +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + + +WIDEVINE_SOC_VENDOR_NAME ?= Google +WIDEVINE_SOC_MODEL_NAME ?= $(PLATFORM) +WIDEVINE_TEE_OS_NAME ?= Trusty +WIDEVINE_TEE_OS_VERSION ?= 0.0 # TODO add version +WIDEVINE_FORM_FACTOR ?= phone+tablet +WIDEVINE_OEMCRYPTO_IMPLEMENTER ?= Widevine + +MODULE_DEFINES += \ + OPK_CONFIG_SOC_VENDOR_NAME=$(WIDEVINE_SOC_VENDOR_NAME) \ + OPK_CONFIG_SOC_MODEL_NAME=$(WIDEVINE_SOC_MODEL_NAME) \ + OPK_CONFIG_TEE_OS_NAME=$(WIDEVINE_TEE_OS_NAME) \ + OPK_CONFIG_TEE_OS_VERSION=$(WIDEVINE_TEE_OS_VERSION) \ + OPK_CONFIG_DEVICE_FORM_FACTOR=$(WIDEVINE_FORM_FACTOR) \ + OPK_CONFIG_IMPLEMENTER_NAME=$(WIDEVINE_OEMCRYPTO_IMPLEMENTER) \ + +# oemcrypto.h will declare constants as C++-style statics. +# C sources do not like this, so change the behavior. +MODULE_CFLAGS += -DNO_OEMCRYPTO_VARIABLE_DEFINITIONS + +# Ensure API entry points are renamed in a predictable manner. +# TODO: can we remove this? +MODULE_CFLAGS += -DOEMCRYPTO_TA_TEST_ONLY + +# TODO: remove when the prototypes in oemcrypto.h are strict. +MODULE_CFLAGS += -Wno-strict-prototypes + +MODULE_DEFINES += \ + 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__ + +MODULE_INCLUDES += \ + $(REF_DIR)/include \ + $(SHARED_DIR)/include \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + +MODULE_SRCS += \ + $(REF_DIR)/widevine_app.c \ + $(REF_DIR)/secure_buffer.c \ + $(REF_DIR)/tee_context.c \ + $(SHARED_DIR)/shared_memory.c \ + $(SHARED_DIR)/widevine_ipc_protocol.c \ + $(APP_DIR)/wtpi_reference/cose_util.c \ + $(APP_DIR)/wtpi_reference/crypto_util.c \ + $(APP_DIR)/wtpi_reference/ecc_util.c \ + $(APP_DIR)/wtpi_reference/renewal_util.c \ + $(APP_DIR)/wtpi_reference/rsa_util.c \ + $(APP_DIR)/wtpi_reference/wtpi_abort.c \ + $(APP_DIR)/wtpi_reference/wtpi_clock_and_gn_layer1.c \ + $(APP_DIR)/wtpi_reference/wtpi_config.c \ + $(APP_DIR)/wtpi_reference/wtpi_crc32.c \ + $(APP_DIR)/wtpi_reference/wtpi_crypto_wrap_asymmetric.c \ + $(APP_DIR)/wtpi_reference/wtpi_device_renewal_layer1.c \ + $(APP_DIR)/wtpi_reference/wtpi_decrypt_sample.c \ + $(APP_DIR)/wtpi_reference/wtpi_idle.c \ + $(APP_DIR)/wtpi_reference/wtpi_logging.c \ + $(APP_DIR)/wtpi_reference/wtpi_root_of_trust_layer1.c \ + $(REF_IMPL_DIR)/wtpi_clock_layer2.c \ + $(REF_IMPL_DIR)/wtpi_crypto_asymmetric.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.c \ + $(REF_IMPL_DIR)/wtpi_provisioning_4.c \ + $(REF_IMPL_DIR)/wtpi_root_of_trust_layer2.c \ + $(REF_IMPL_DIR)/transport_interface.c \ + $(APP_DIR)/wtpi_reference/wtpi_device_key.c \ + $(APP_DIR)/wtpi_reference/device_key_util.c \ + $(APP_DIR)/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c \ + $(APP_DIR)/wtpi_useless/wtpi_device_key_access.c \ + $(APP_DIR)/wtpi_reference/wtpi_device_renewal_layer2.c \ + $(REF_DIR)/system_specific.c \ + +MODULE_LIBRARY_DEPS += \ + 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/libc-trusty \ + trusty/user/base/lib/storage \ + trusty/user/base/lib/system_state \ + trusty/user/base/lib/tipc \ + external/boringssl \ + external/open-dice \ + +include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk + +MODULE_SRCS += \ + $(opk_base_ta_sources) \ + +MODULE_INCLUDES += \ + $(opk_base_ta_includes) \ + +# Before including trusted_app.mk, this is the root build directory +LIBOEMCRYPTO_OUT_DIR := $(BUILDDIR) + +LIBOEMCRYPTO_SRC_DIR := $(REF_DIR)/liboemcrypto + +include make/trusted_app.mk + +# Build liboemcrypto.so +LIBOEMCRYPTO_BUILD_DIR := $(BUILDDIR)/liboemcrypto +include $(LIBOEMCRYPTO_SRC_DIR)/liboemcrypto-inc.mk diff --git a/oemcrypto/opk/ports/trusty/ta/secure_buffer.c b/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c similarity index 98% rename from oemcrypto/opk/ports/trusty/ta/secure_buffer.c rename to oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c index af059cc..6b80085 100644 --- a/oemcrypto/opk/ports/trusty/ta/secure_buffer.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c @@ -112,7 +112,7 @@ void cleanup_secure_buffers(void) { finish_dma(addr, size, DMA_FLAG_FROM_DEVICE); /* Unmap */ if (munmap(addr, size)) { - TLOGE(" %zu munmap failed %p/%zu\n", i, addr, size); + TLOGE(" %zu munmap failed, size %zu\n", i, size); } } diff --git a/oemcrypto/opk/ports/trusty/ta/secure_buffer.h b/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/secure_buffer.h rename to oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.h diff --git a/oemcrypto/opk/ports/trusty/ta/shared/include/macros.h b/oemcrypto/opk/ports/trusty/ta/reference/shared/include/macros.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/shared/include/macros.h rename to oemcrypto/opk/ports/trusty/ta/reference/shared/include/macros.h diff --git a/oemcrypto/opk/ports/trusty/ta/shared/include/trusty_shared_memory.h b/oemcrypto/opk/ports/trusty/ta/reference/shared/include/trusty_shared_memory.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/shared/include/trusty_shared_memory.h rename to oemcrypto/opk/ports/trusty/ta/reference/shared/include/trusty_shared_memory.h diff --git a/oemcrypto/opk/ports/trusty/ta/shared/include/widevine_ipc_protocol.h b/oemcrypto/opk/ports/trusty/ta/reference/shared/include/widevine_ipc_protocol.h similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/shared/include/widevine_ipc_protocol.h rename to oemcrypto/opk/ports/trusty/ta/reference/shared/include/widevine_ipc_protocol.h diff --git a/oemcrypto/opk/ports/trusty/ta/shared/shared_memory.c b/oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/shared/shared_memory.c rename to oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c diff --git a/oemcrypto/opk/ports/trusty/ta/shared/widevine_ipc_protocol.c b/oemcrypto/opk/ports/trusty/ta/reference/shared/widevine_ipc_protocol.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/shared/widevine_ipc_protocol.c rename to oemcrypto/opk/ports/trusty/ta/reference/shared/widevine_ipc_protocol.c diff --git a/oemcrypto/opk/ports/trusty/ta/system_specific.c b/oemcrypto/opk/ports/trusty/ta/reference/system_specific.c similarity index 79% rename from oemcrypto/opk/ports/trusty/ta/system_specific.c rename to oemcrypto/opk/ports/trusty/ta/reference/system_specific.c index 76bfd86..c28202e 100644 --- a/oemcrypto/opk/ports/trusty/ta/system_specific.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/system_specific.c @@ -16,11 +16,6 @@ #include -#include -#define TLOG_TAG "widevine" - -// Any system-specific functionality to validate the ipc buffer int system_specific_validate_ipc_buffer(int handle) { return 0; } -// Any system-specific functionality to validate the secure buffer -int system_specific_validate_secure_output_buffer(int handle) { return 0; } +int system_specific_validate_secure_output_buffer(int handle) { return -1; } diff --git a/oemcrypto/opk/ports/trusty/ta/tee_context.c b/oemcrypto/opk/ports/trusty/ta/reference/tee_context.c similarity index 92% rename from oemcrypto/opk/ports/trusty/ta/tee_context.c rename to oemcrypto/opk/ports/trusty/ta/reference/tee_context.c index 066b3ca..acf00cb 100644 --- a/oemcrypto/opk/ports/trusty/ta/tee_context.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/tee_context.c @@ -16,7 +16,8 @@ #include "include/tee_context.h" -static tee_context ctx = {STORAGE_INVALID_SESSION, STORAGE_INVALID_SESSION}; +static tee_context ctx = {STORAGE_INVALID_SESSION, STORAGE_INVALID_SESSION, + STORAGE_INVALID_SESSION}; tee_context* get_tee_context() { return &ctx; diff --git a/oemcrypto/opk/ports/trusty/ta/widevine_app.c b/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/widevine_app.c rename to oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c diff --git a/oemcrypto/opk/ports/trusty/ta/rules.mk b/oemcrypto/opk/ports/trusty/ta/rules.mk deleted file mode 100644 index eba6526..0000000 --- a/oemcrypto/opk/ports/trusty/ta/rules.mk +++ /dev/null @@ -1,171 +0,0 @@ -# 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) - -MANIFEST := $(LOCAL_DIR)/manifest.json - -SHARED_DIR := $(LOCAL_DIR)/shared -IMPL_DIR := $(LOCAL_DIR)/interface_impls -CDM_DIR := ../../ -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 - -# oemcrypto.h will declare constants as C++-style statics. -# C sources do not like this, so change the behavior. -MODULE_CFLAGS += -DNO_OEMCRYPTO_VARIABLE_DEFINITIONS - -# Ensure API entry points are renamed in a predictable manner. -# TODO: can we remove this? -MODULE_CFLAGS += -DOEMCRYPTO_TA_TEST_ONLY - -# TODO: remove when the prototypes in oemcrypto.h are strict. -MODULE_CFLAGS += -Wno-strict-prototypes - -MODULE_DEFINES += \ - WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \ - -# The base Trusty app. -MODULE_SRCS += \ - $(LOCAL_DIR)/widevine_app.c \ - $(LOCAL_DIR)/secure_buffer.c \ - $(LOCAL_DIR)/tee_context.c \ - $(IMPL_DIR)/device_key_v0.c \ - $(IMPL_DIR)/wtpi_clock_layer2.c \ - $(IMPL_DIR)/wtpi_crypto_and_key_management_layer1_openssl.c \ - $(IMPL_DIR)/wtpi_crypto_asymmetric.c \ - $(IMPL_DIR)/wtpi_device_key.c \ - $(IMPL_DIR)/wtpi_secure_buffer_access.c \ - $(IMPL_DIR)/wtpi_initialize_terminate.c \ - $(IMPL_DIR)/wtpi_config.c \ - $(IMPL_DIR)/wtpi_persistent_storage.c \ - $(IMPL_DIR)/wtpi_root_of_trust_layer2.c \ - $(IMPL_DIR)/transport_interface.c \ - $(SHARED_DIR)/shared_memory.c \ - $(SHARED_DIR)/widevine_ipc_protocol.c \ - -MODULE_INCLUDES += \ - $(LOCAL_DIR)/include \ - $(SHARED_DIR)/include \ - - -# Code to deserialize API calls across IPC and serialize responses. -MODULE_SRCS += \ - $(ODK_DIR)/src/odk.c \ - $(ODK_DIR)/src/odk_message.c \ - $(ODK_DIR)/src/odk_overflow.c \ - $(ODK_DIR)/src/odk_serialize.c \ - $(ODK_DIR)/src/odk_timer.c \ - $(ODK_DIR)/src/odk_util.c \ - $(ODK_DIR)/src/serialization_base.c \ - $(SERIALIZATION_DIR)/common/bump_allocator.c \ - $(SERIALIZATION_DIR)/common/common_special_cases.c \ - $(SERIALIZATION_DIR)/common/GEN_common_serializer.c \ - $(SERIALIZATION_DIR)/common/length_types.c \ - $(SERIALIZATION_DIR)/common/log_macros.c \ - $(SERIALIZATION_DIR)/common/marshaller_base.c \ - $(SERIALIZATION_DIR)/common/opk_init.c \ - $(SERIALIZATION_DIR)/common/opk_serialization_base.c \ - $(SERIALIZATION_DIR)/common/shared_buffer_allocator.c \ - $(SERIALIZATION_DIR)/tee/GEN_dispatcher.c \ - $(SERIALIZATION_DIR)/tee/GEN_tee_serializer.c \ - $(SERIALIZATION_DIR)/tee/tee_os_type.c \ - $(SERIALIZATION_DIR)/tee/tee_version.c \ - $(SERIALIZATION_DIR)/tee/tee_special_cases.c \ - -# HACK: include dirs out of order to deal with header file masking. - -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 \ - -# Generic Widevine app code -MODULE_SRCS += \ - $(APP_DIR)/oemcrypto.c \ - $(APP_DIR)/oemcrypto_asymmetric_key_table.c \ - $(APP_DIR)/oemcrypto_entitled_key_session.c \ - $(APP_DIR)/oemcrypto_entitled_key_session_table.c \ - $(APP_DIR)/oemcrypto_key.c \ - $(APP_DIR)/oemcrypto_key_control_block.c \ - $(APP_DIR)/oemcrypto_key_table.c \ - $(APP_DIR)/oemcrypto_object_table.c \ - $(APP_DIR)/oemcrypto_output.c \ - $(APP_DIR)/oemcrypto_overflow.c \ - $(APP_DIR)/oemcrypto_serialized_usage_table.c \ - $(APP_DIR)/oemcrypto_session.c \ - $(APP_DIR)/oemcrypto_session_key_table.c \ - $(APP_DIR)/oemcrypto_session_table.c \ - $(APP_DIR)/oemcrypto_session_type.c \ - $(APP_DIR)/oemcrypto_usage_table.c \ - $(APP_DIR)/oemcrypto_wall_clock.c \ - $(APP_DIR)/wtpi_reference/crypto_util.c \ - $(APP_DIR)/wtpi_reference/ecc_util.c \ - $(APP_DIR)/wtpi_reference/rsa_util.c \ - $(APP_DIR)/wtpi_reference/wtpi_abort.c \ - $(APP_DIR)/wtpi_reference/wtpi_clock_and_gn_layer1.c \ - $(APP_DIR)/wtpi_reference/wtpi_crc32.c \ - $(APP_DIR)/wtpi_reference/wtpi_crypto_wrap_asymmetric.c \ - $(APP_DIR)/wtpi_reference/wtpi_decrypt_sample.c \ - $(APP_DIR)/wtpi_reference/wtpi_idle.c \ - $(APP_DIR)/wtpi_reference/wtpi_logging.c \ - $(APP_DIR)/wtpi_reference/wtpi_root_of_trust_layer1.c \ - $(APP_DIR)/wtpi_reference/wtpi_device_renewal_layer1.c \ - $(APP_DIR)/wtpi_reference/wtpi_device_renewal_layer2.c \ - $(APP_DIR)/wtpi_reference/renewal_util.c \ - -MODULE_INCLUDES += \ - $(APP_DIR) \ - $(APP_DIR)/wtpi \ - $(APP_DIR)/wtpi_reference \ - -MODULE_LIBRARY_DEPS += \ - 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/libc-trusty \ - trusty/user/base/lib/storage \ - trusty/user/base/lib/system_state \ - trusty/user/base/lib/tipc \ - external/boringssl \ - - -# TODO: abstract out system-specific customization. -MODULE_SRCS += \ - $(LOCAL_DIR)/system_specific.c \ - -# Before including trusted_app.mk, this is the root build directory -LIBOEMCRYPTO_OUT_DIR := $(BUILDDIR) - -LIBOEMCRYPTO_SRC_DIR := $(LOCAL_DIR)/liboemcrypto - -include make/trusted_app.mk - -# Build liboemcrypto.so -LIBOEMCRYPTO_BUILD_DIR := $(BUILDDIR)/liboemcrypto -include $(LIBOEMCRYPTO_SRC_DIR)/liboemcrypto-inc.mk diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.c b/oemcrypto/opk/serialization/common/GEN_common_serializer.c index 7956e1b..5aed9c1 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.c +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.c @@ -108,6 +108,8 @@ bool Is_Valid_OEMCryptoResult(uint32_t value) { case 2000: /* OPK_ERROR_BASE */ case 2001: /* OPK_ERROR_INCOMPATIBLE_VERSION */ case 2002: /* OPK_ERROR_NO_PERSISTENT_DATA */ + case 2003: /* OPK_ERROR_PREHOOK_FAILURE */ + case 2004: /* OPK_ERROR_POSTHOOK_FAILURE */ return true; default: return false; @@ -127,6 +129,16 @@ bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value) { } } +bool Is_Valid_OEMCrypto_ProvisioningRenewalType(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_NoRenewal */ + case 1: /* OEMCrypto_RenewalACert */ + return true; + default: + return false; + } +} + bool Is_Valid_OEMCrypto_LicenseType(uint32_t value) { switch (value) { case 0: /* OEMCrypto_ContentLicense */ @@ -147,6 +159,17 @@ bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value) { } } +bool Is_Valid_OEMCrypto_TimerDelayBase(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_License_Start */ + case 1: /* OEMCrypto_License_Load */ + case 2: /* OEMCrypto_First_Decrypt */ + return true; + default: + return false; + } +} + bool Is_Valid_OEMCryptoBufferType(uint32_t value) { switch (value) { case 0: /* OEMCrypto_BufferType_Clear */ @@ -252,6 +275,18 @@ bool Is_Valid_OEMCrypto_WatermarkingSupport(uint32_t value) { } } +bool Is_Valid_OEMCrypto_SignatureHashAlgorithm(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_SHA1 */ + case 1: /* OEMCrypto_SHA2_256 */ + case 2: /* OEMCrypto_SHA2_384 */ + case 3: /* OEMCrypto_SHA2_512 */ + return true; + default: + return false; + } +} + bool Is_Valid_OEMCrypto_IdleState(uint32_t value) { switch (value) { case 0: /* OEMCrypto_NoCryptoActivity */ @@ -360,9 +395,10 @@ void OPK_Pack_OEMCrypto_SampleDescription( const bool is_null = objs == NULL || OPK_LengthIsNull(count); if (!OPK_PackBoolValue(odk_message, is_null)) { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + const uint8_t* new_address = (const uint8_t*)objs + i * size; OPK_Pack_OEMCrypto_SubSampleDescription( odk_message, - (const OEMCrypto_SubSampleDescription*)(objs + i * size)); + (const OEMCrypto_SubSampleDescription*)(const void*)new_address); } } } @@ -388,15 +424,6 @@ void OPK_Pack_OEMCrypto_EntitledContentKeyObject( OPK_Pack_uint32_t(msg, (const OEMCryptoCipherMode*)&obj->cipher_mode); } -void OPK_Pack_OEMCrypto_KeyRefreshObject( - ODK_Message* msg, OEMCrypto_KeyRefreshObject const* obj) { - OPK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id); - OPK_Pack_OEMCrypto_Substring( - msg, (const OEMCrypto_Substring*)&obj->key_control_iv); - OPK_Pack_OEMCrypto_Substring(msg, - (const OEMCrypto_Substring*)&obj->key_control); -} - void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc_V15( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc_V15 const* obj) { OPK_Pack_size_t(msg, (const size_t*)&obj->encrypt); @@ -416,6 +443,15 @@ void OPK_Pack_OEMCrypto_EntitledContentKeyObject_V16( msg, (const OEMCrypto_Substring*)&obj->content_key_data); } +void OPK_Pack_OEMCrypto_KeyRefreshObject( + ODK_Message* msg, OEMCrypto_KeyRefreshObject const* obj) { + OPK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id); + OPK_Pack_OEMCrypto_Substring( + msg, (const OEMCrypto_Substring*)&obj->key_control_iv); + OPK_Pack_OEMCrypto_Substring(msg, + (const OEMCrypto_Substring*)&obj->key_control); +} + void OPK_Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj) { OPK_Unpack_size_t(msg, &obj->offset); @@ -509,9 +545,10 @@ void OPK_Unpack_OEMCrypto_SampleDescription(ODK_Message* msg, ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); } else { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + uint8_t* new_address = (uint8_t*)(*address) + size * i; OPK_Unpack_OEMCrypto_SubSampleDescription( odk_message, - (OEMCrypto_SubSampleDescription*)((*address) + size * i)); + (OEMCrypto_SubSampleDescription*)((void*)new_address)); } } } @@ -537,13 +574,6 @@ void OPK_Unpack_OEMCrypto_EntitledContentKeyObject( OPK_Unpack_uint32_t(msg, &obj->cipher_mode); } -void OPK_Unpack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, - OEMCrypto_KeyRefreshObject* obj) { - OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_id); - OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control_iv); - OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control); -} - void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc_V15( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc_V15* obj) { OPK_Unpack_size_t(msg, &obj->encrypt); @@ -559,6 +589,13 @@ void OPK_Unpack_OEMCrypto_EntitledContentKeyObject_V16( OPK_Unpack_OEMCrypto_Substring(msg, &obj->content_key_data); } +void OPK_Unpack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, + OEMCrypto_KeyRefreshObject* obj) { + OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_id); + OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control_iv); + OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control); +} + void OPK_PackNullable_uint32_t(ODK_Message* msg, const uint32_t* value) { OPK_PackBoolValue(msg, value == NULL); if (value) { @@ -597,19 +634,19 @@ void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value) { OPK_Unpack_size_t(msg, *value); } } -void OPK_PackNullable_OEMCrypto_KeyRefreshObject( - ODK_Message* msg, const OEMCrypto_KeyRefreshObject* value) { +void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value) { OPK_PackBoolValue(msg, value == NULL); if (value) { - OPK_Pack_OEMCrypto_KeyRefreshObject(msg, value); + OPK_Pack_OEMCrypto_EntitledContentKeyObject(msg, value); } } -void OPK_UnpackNullable_OEMCrypto_KeyRefreshObject( - ODK_Message* msg, OEMCrypto_KeyRefreshObject** value) { +void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value) { if (OPK_UnpackIsNull(msg)) { *value = NULL; } else { - OPK_Unpack_OEMCrypto_KeyRefreshObject(msg, *value); + OPK_Unpack_OEMCrypto_EntitledContentKeyObject(msg, *value); } } void OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( @@ -688,18 +725,3 @@ void OPK_UnpackAlloc_int(ODK_Message* msg, int** value) { OPK_Unpack_int(msg, *value); } } -void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value) { - OPK_PackBoolValue(msg, value == NULL); - if (value) { - OPK_Pack_OEMCrypto_EntitledContentKeyObject(msg, value); - } -} -void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value) { - if (OPK_UnpackIsNull(msg)) { - *value = NULL; - } else { - OPK_Unpack_OEMCrypto_EntitledContentKeyObject(msg, *value); - } -} diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.h b/oemcrypto/opk/serialization/common/GEN_common_serializer.h index 6146680..3362471 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.h +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.h @@ -20,8 +20,10 @@ extern "C" { bool SuccessResult(OEMCryptoResult result); bool Is_Valid_OEMCryptoResult(uint32_t value); bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value); +bool Is_Valid_OEMCrypto_ProvisioningRenewalType(uint32_t value); bool Is_Valid_OEMCrypto_LicenseType(uint32_t value); bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value); +bool Is_Valid_OEMCrypto_TimerDelayBase(uint32_t value); bool Is_Valid_OEMCryptoBufferType(uint32_t value); bool Is_Valid_OEMCryptoCipherMode(uint32_t value); bool Is_Valid_OEMCrypto_Algorithm(uint32_t value); @@ -30,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_WatermarkingSupport(uint32_t value); +bool Is_Valid_OEMCrypto_SignatureHashAlgorithm(uint32_t value); bool Is_Valid_OEMCrypto_IdleState(uint32_t value); bool Is_Valid_OEMCrypto_Security_Level(uint32_t value); void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg, @@ -54,12 +57,12 @@ void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc const* obj); void OPK_Pack_OEMCrypto_EntitledContentKeyObject( ODK_Message* msg, OEMCrypto_EntitledContentKeyObject const* obj); -void OPK_Pack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, - OEMCrypto_KeyRefreshObject const* obj); void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc_V15( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc_V15 const* obj); void OPK_Pack_OEMCrypto_EntitledContentKeyObject_V16( ODK_Message* msg, OEMCrypto_EntitledContentKeyObject_V16 const* obj); +void OPK_Pack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, + OEMCrypto_KeyRefreshObject const* obj); void OPK_Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj); void OPK_Unpack_OEMCrypto_DTCP2_CMI_Descriptor_0( ODK_Message* msg, OEMCrypto_DTCP2_CMI_Descriptor_0* obj); @@ -80,22 +83,22 @@ void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc* obj); void OPK_Unpack_OEMCrypto_EntitledContentKeyObject( ODK_Message* msg, OEMCrypto_EntitledContentKeyObject* obj); -void OPK_Unpack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, - OEMCrypto_KeyRefreshObject* obj); void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc_V15( ODK_Message* msg, OEMCrypto_CENCEncryptPatternDesc_V15* obj); void OPK_Unpack_OEMCrypto_EntitledContentKeyObject_V16( ODK_Message* msg, OEMCrypto_EntitledContentKeyObject_V16* obj); +void OPK_Unpack_OEMCrypto_KeyRefreshObject(ODK_Message* msg, + OEMCrypto_KeyRefreshObject* obj); void OPK_PackNullable_uint32_t(ODK_Message* msg, const uint32_t* value); void OPK_UnpackNullable_uint32_t(ODK_Message* msg, uint32_t** value); void OPK_UnpackAlloc_uint32_t(ODK_Message* msg, uint32_t** value); void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value); void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value); void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value); -void OPK_PackNullable_OEMCrypto_KeyRefreshObject( - ODK_Message* msg, const OEMCrypto_KeyRefreshObject* value); -void OPK_UnpackNullable_OEMCrypto_KeyRefreshObject( - ODK_Message* msg, OEMCrypto_KeyRefreshObject** value); +void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value); +void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value); void OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( ODK_Message* msg, const OEMCrypto_CENCEncryptPatternDesc* value); void OPK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc( @@ -112,10 +115,6 @@ void OPK_UnpackAlloc_OEMCrypto_DestBufferDesc(ODK_Message* msg, void OPK_PackNullable_int(ODK_Message* msg, const int* value); void OPK_UnpackNullable_int(ODK_Message* msg, int** value); void OPK_UnpackAlloc_int(ODK_Message* msg, int** value); -void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value); -void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value); #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/serialization/common/bump_allocator.c b/oemcrypto/opk/serialization/common/bump_allocator.c index 1ffeec5..e2ea685 100644 --- a/oemcrypto/opk/serialization/common/bump_allocator.c +++ b/oemcrypto/opk/serialization/common/bump_allocator.c @@ -26,19 +26,28 @@ static size_t buffer_offset = 0; * allocations are aligned to 16 byte boundaries */ UBSAN_IGNORE_UNSIGNED_OVERFLOW void* OPK_BumpAllocate(size_t nbytes) { - size_t alignment_pad = (ALIGN - buffer_offset) & (ALIGN - 1); - size_t new_offset = 0; - if (odk_add_overflow_ux(buffer_offset, nbytes + alignment_pad, &new_offset) || - (new_offset > BUFFER_SIZE)) { - LOGE("failed: %zu / %d bytes free, requested %zu", - BUFFER_SIZE - buffer_offset, BUFFER_SIZE, nbytes); + /* Calcuate the next aligned address to be allocated from. The ALIGN must be a + * power of two for the calculation below to work. See details at + * https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding */ + uint8_t* const next_aligned_address = + (uint8_t*)(((uintptr_t)buffer + buffer_offset + ALIGN - 1) & + ~(ALIGN - 1)); + const size_t next_aligned_offset = next_aligned_address - buffer; + if (next_aligned_offset >= BUFFER_SIZE) { + LOGE("failed: the next aligned address out of range"); return NULL; } - LOGV("allocated %zu bytes at offset %zu, %zu free", nbytes, buffer_offset, - BUFFER_SIZE - buffer_offset); - uint8_t* result = buffer + buffer_offset; + size_t new_offset = 0; + if (odk_add_overflow_ux(next_aligned_offset, nbytes, &new_offset) || + (new_offset > BUFFER_SIZE)) { + LOGE("failed: %zu / %d bytes free, requested %zu", + BUFFER_SIZE - next_aligned_offset, BUFFER_SIZE, nbytes); + return NULL; + } + LOGV("allocated %zu bytes at offset %zu, %zu free", nbytes, + next_aligned_offset, BUFFER_SIZE - new_offset); buffer_offset = new_offset; - return result; + return next_aligned_address; } void OPK_BumpAllocator_Reset(void) { diff --git a/oemcrypto/opk/serialization/common/common_special_cases.c b/oemcrypto/opk/serialization/common/common_special_cases.c index d0ea673..edd2019 100644 --- a/oemcrypto/opk/serialization/common/common_special_cases.c +++ b/oemcrypto/opk/serialization/common/common_special_cases.c @@ -47,10 +47,8 @@ void OPK_Pack_OEMCrypto_DestBufferDesc(ODK_Message* message, break; } case OEMCrypto_BufferType_Secure: - if (OPK_Get_OSType() == OPK_RICH_OS) { - /* let the secure buffer OS interface pack the buffer info as needed */ - TOS_SecureBuffer_Pack(message, obj); - } + /* let the secure buffer OS interface pack the buffer info as needed */ + TOS_SecureBuffer_Pack(message, obj); break; case OEMCrypto_BufferType_Direct: OPK_Pack_bool(message, &obj->buffer.direct.is_video); @@ -78,9 +76,9 @@ void OPK_Unpack_OEMCrypto_DestBufferDesc(ODK_Message* message, /* map */ true, /* is output */ true); break; case OEMCrypto_BufferType_Secure: + /* let the secure buffer OS interface unpack the buffer info */ + TOS_SecureBuffer_Unpack(message, obj); if (OPK_Get_OSType() == OPK_TRUSTED_OS) { - /* let the secure buffer OS interface unpack the buffer info */ - TOS_SecureBuffer_Unpack(message, obj); /* double-check the size */ if (!TOS_SecureBuffer_CheckSize( obj->buffer.secure.secure_buffer, @@ -92,5 +90,8 @@ void OPK_Unpack_OEMCrypto_DestBufferDesc(ODK_Message* message, case OEMCrypto_BufferType_Direct: OPK_Unpack_bool(message, &obj->buffer.direct.is_video); break; + default: + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_PARSE_ERROR); + break; } } diff --git a/oemcrypto/opk/serialization/common/include/length_types.h b/oemcrypto/opk/serialization/common/include/length_types.h index 3fb685b..ed68436 100644 --- a/oemcrypto/opk/serialization/common/include/length_types.h +++ b/oemcrypto/opk/serialization/common/include/length_types.h @@ -32,7 +32,7 @@ LengthType OPK_ToLengthType(size_t length); LengthType OPK_FromSizeTPtr(const size_t* length); LengthType OPK_FromU32Ptr(const uint32_t* length); LengthType OPK_FromSizeTPtrPtr(size_t* const* length); -LengthType OPK_FromUint32PtrPtr(uint32_t* const* length); +LengthType OPK_FromU32PtrPtr(uint32_t* const* length); size_t OPK_ToSizeT(LengthType length_type); bool OPK_LengthIsNull(LengthType length_type); diff --git a/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h b/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h index 24c6202..0ed30ff 100644 --- a/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h +++ b/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h @@ -15,6 +15,8 @@ extern "C" { #include #include +#include "odk_message.h" + typedef enum { SHARED_BUFFER_TYPE_INVALID, SHARED_BUFFER_TYPE_INPUT, @@ -26,8 +28,10 @@ typedef enum { */ bool OPK_SharedBuffer_Initialize(void); void OPK_SharedBuffer_Terminate(void); -uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, - bool copy_out, bool is_output); +ODK_MessageStatus OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, + bool copy_in, bool copy_out, + bool is_output, + uint8_t** shared_address); uint8_t* OPK_SharedBuffer_NextBuffer(void); uint8_t* OPK_SharedBuffer_NextOutputBuffer(void); uint8_t* OPK_SharedBuffer_GetAddress(void); diff --git a/oemcrypto/opk/serialization/common/log_macros.c b/oemcrypto/opk/serialization/common/log_macros.c index 10e4e52..1f03e0e 100644 --- a/oemcrypto/opk/serialization/common/log_macros.c +++ b/oemcrypto/opk/serialization/common/log_macros.c @@ -45,6 +45,8 @@ const char* OPK_MessageStatus_Str(ODK_MessageStatus status) { return "MAP_SHARED_MEMORY_FAILED"; case MESSAGE_STATUS_SECURE_BUFFER_ERROR: return "SECURE_BUFFER_ERROR"; + case MESSAGE_STATUS_BUFFER_TOO_LARGE: + return "BUFFER_TOO_LARGE"; default: break; } diff --git a/oemcrypto/opk/serialization/common/opk_init.c b/oemcrypto/opk/serialization/common/opk_init.c index 8758b41..c59ef50 100644 --- a/oemcrypto/opk/serialization/common/opk_init.c +++ b/oemcrypto/opk/serialization/common/opk_init.c @@ -4,13 +4,7 @@ * License Agreement. */ -#ifndef OPK_INIT_H_ -#define OPK_INIT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - +#include "opk_init.h" #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" #include "tos_transport_interface.h" @@ -37,9 +31,3 @@ void OPK_Terminate(void) { OPK_SharedBuffer_Terminate(); TOS_Transport_Terminate(); } - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // OPK_INIT_H_ diff --git a/oemcrypto/opk/serialization/common/opk_serialization_base.c b/oemcrypto/opk/serialization/common/opk_serialization_base.c index 537fff1..f579a5f 100644 --- a/oemcrypto/opk/serialization/common/opk_serialization_base.c +++ b/oemcrypto/opk/serialization/common/opk_serialization_base.c @@ -191,15 +191,16 @@ void OPK_PackSharedBuffer(ODK_Message* message, const uint8_t* address, * happen is if the parameter being packed is an output and so will of * course be writeable. */ - shared_address = OPK_SharedBuffer_Allocate( - (uint8_t*)(uintptr_t)address, len, copy_in, copy_out, is_output); - if (shared_address) { + ODK_MessageStatus sts = + OPK_SharedBuffer_Allocate((uint8_t*)(uintptr_t)address, len, copy_in, + copy_out, is_output, &shared_address); + if (sts == MESSAGE_STATUS_OK) { MDBG(" -> " BLUE "new map " COLOR_OFF "%p..%p [len=%zu]", (const void*)shared_address, (const void*)(shared_address + len - 1), len); } else { MDBG(RED " -> map failed: NULL" COLOR_OFF); - ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED); + ODK_MESSAGE_SETSTATUS(message, sts); } } else { if (address) { @@ -256,7 +257,7 @@ void OPK_Unpack_bool(ODK_Message* message, bool* value) { } static uint64_t Unpack64(ODK_Message* message) { - uint8_t buf[sizeof(uint64_t)]; + uint8_t buf[sizeof(uint64_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); uint64_t u64 = buf[0]; u64 |= (uint64_t)buf[1] << 8; @@ -283,13 +284,13 @@ void OPK_Unpack_size_t(ODK_Message* message, size_t* value) { void OPK_Unpack_uint8_t(ODK_Message* message, uint8_t* value) { if (!CheckTag(message, TAG_UINT8)) return; - UnpackBytes(message, (uint8_t*)value, sizeof(*value)); + UnpackBytes(message, value, sizeof(*value)); } void OPK_Unpack_uint16_t(ODK_Message* message, uint16_t* value) { if (!CheckTag(message, TAG_UINT16)) return; assert(value); - uint8_t buf[sizeof(uint16_t)]; + uint8_t buf[sizeof(uint16_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); *value = buf[0]; *value |= (uint16_t)buf[1] << 8; @@ -298,7 +299,7 @@ void OPK_Unpack_uint16_t(ODK_Message* message, uint16_t* value) { void OPK_Unpack_uint32_t(ODK_Message* message, uint32_t* value) { if (!CheckTag(message, TAG_UINT32)) return; assert(value); - uint8_t buf[sizeof(uint32_t)]; + uint8_t buf[sizeof(uint32_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); *value = buf[0]; *value |= (uint32_t)buf[1] << 8; @@ -413,15 +414,15 @@ void OPK_UnpackSharedBuffer(ODK_Message* message, uint8_t** address, */ bool copy_in = false; bool copy_out = false; - shared_address = OPK_SharedBuffer_Allocate(*address, len, copy_in, - copy_out, is_output); - if (shared_address) { + ODK_MessageStatus sts = OPK_SharedBuffer_Allocate( + *address, len, copy_in, copy_out, is_output, &shared_address); + if (sts == MESSAGE_STATUS_OK) { MDBG(" -> " BLUE "new map " COLOR_OFF "%p..%p [len=%zu]", (const void*)shared_address, (const void*)(shared_address + len - 1), len); } else { MDBG(RED " -> map failed: NULL" COLOR_OFF); - ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED); + ODK_MESSAGE_SETSTATUS(message, sts); } *address = shared_address; } else { diff --git a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c index 711cc23..1c0efbd 100644 --- a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c +++ b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c @@ -11,6 +11,7 @@ #include "oemcrypto_overflow.h" #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" +#include "tos_transport_interface.h" /* * The Shared Buffer Allocator provides functions for allocating and @@ -100,7 +101,7 @@ static size_t buffer_count_ = 0; /* * Initialize shared memory state variables. */ -bool OPK_SharedBuffer_Initialize() { +bool OPK_SharedBuffer_Initialize(void) { if (TOS_SharedMemory_Allocate(TOS_SharedMemory_AvailableSize())) { OPK_SharedBuffer_Reset(); return true; @@ -111,7 +112,7 @@ bool OPK_SharedBuffer_Initialize() { /* * Release shared memory resources */ -void OPK_SharedBuffer_Terminate() { +void OPK_SharedBuffer_Terminate(void) { OPK_SharedBuffer_Reset(); TOS_SharedMemory_Release(); } @@ -149,20 +150,25 @@ void OPK_SharedBuffer_Reset(void) { * Returns: * The address of the allocation or NULL if allocation fails */ -uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, - bool copy_out, bool is_output) { +ODK_MessageStatus OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, + bool copy_in, bool copy_out, + bool is_output, + uint8_t** shared_address) { size_t index = next_buffer_index_; + if (shared_address == NULL) { + return MESSAGE_STATUS_NULL_POINTER_ERROR; + } if (index >= MAX_SHARED_BUFFERS) { LOGE("Exceeded max shared buffer allocations"); - return NULL; + return MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED; } size_t new_offset = 0; if (OPK_AddOverflowUX(next_buffer_offset_, size, &new_offset)) { - return NULL; + return MESSAGE_STATUS_OVERFLOW_ERROR; } if (new_offset > TOS_SharedMemory_GetSize()) { LOGE("Insufficient shared memory"); - return NULL; + return MESSAGE_STATUS_BUFFER_TOO_LARGE; } Allocation* alloc = &allocations_[index]; @@ -177,7 +183,8 @@ uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, next_buffer_offset_ = new_offset; next_buffer_index_++; buffer_count_++; - return buffer_address; + *shared_address = buffer_address; + return MESSAGE_STATUS_OK; } /* diff --git a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c index 0ee5f33..6af6b1b 100644 --- a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c +++ b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c @@ -30,10 +30,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, 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_SetSandbox_Request(sandbox_id, sandbox_id_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -56,6 +61,18 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) { OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + +#ifdef OPK_PRE_HOOK_OEMCRYPTO_INITIALIZE + result = OPK_PreHook_OEMCrypto_Initialize(); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_PREHOOK_FAILURE; + goto cleanup_and_return; + } +#endif +#if (!defined(OPK_PRE_HOOK_OEMCRYPTO_INITIALIZE) && \ + !defined(OPK_POST_HOOK_OEMCRYPTO_INITIALIZE)) || \ + defined(OPK_HOOK_AND_USE_TA_OEMCRYPTO_INITIALIZE) API_Initialize(); if (!OPK_IsVersionCompatible()) { api_result = OPK_ERROR_INCOMPATIBLE_VERSION; @@ -63,12 +80,56 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) { } request = OPK_Pack_Initialize_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); OPK_Unpack_Initialize_Response(&response, &result); + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +#endif +#ifdef OPK_POST_HOOK_OEMCRYPTO_INITIALIZE + result = OPK_PostHook_OEMCrypto_Initialize(); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_POSTHOOK_FAILURE; + goto cleanup_and_return; + } +#endif +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_SetMaxAPIVersion(uint32_t max_version) { + 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_SetMaxAPIVersion_Request(max_version); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_SetMaxAPIVersion_Response(&response, &result); + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -86,10 +147,26 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) { OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + +#ifdef OPK_PRE_HOOK_OEMCRYPTO_TERMINATE + result = OPK_PreHook_OEMCrypto_Terminate(); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_PREHOOK_FAILURE; + goto cleanup_and_return; + } +#endif +#if (!defined(OPK_PRE_HOOK_OEMCRYPTO_TERMINATE) && \ + !defined(OPK_POST_HOOK_OEMCRYPTO_TERMINATE)) || \ + defined(OPK_HOOK_AND_USE_TA_OEMCRYPTO_TERMINATE) API_Initialize(); request = OPK_Pack_Terminate_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -98,6 +175,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) { if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; } +#endif +#ifdef OPK_POST_HOOK_OEMCRYPTO_TERMINATE + result = OPK_PostHook_OEMCrypto_Terminate(); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_POSTHOOK_FAILURE; + goto cleanup_and_return; + } +#endif cleanup_and_return: TOS_Transport_ReleaseMessage(&request); TOS_Transport_ReleaseMessage(&response); @@ -114,10 +200,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Idle(OEMCrypto_IdleState state, 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_Idle_Request(state, os_specific_code); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -140,10 +231,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Wake(void) { 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_Wake_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -167,10 +263,15 @@ OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { 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_OpenSession_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -194,10 +295,15 @@ OEMCrypto_CloseSession(OEMCrypto_SESSION session) { 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_CloseSession_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -215,61 +321,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateEntitledKeySession( - OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_CreateEntitledKeySession_Request(oec_session, key_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_CreateEntitledKeySession_Response(&response, &result, - &key_session); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_RemoveEntitledKeySession(OEMCrypto_SESSION key_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_RemoveEntitledKeySession_Request(key_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_RemoveEntitledKeySession_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -279,12 +330,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( 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_GenerateDerivedKeys_Request( session, mac_key_context, mac_key_context_length, enc_key_context, enc_key_context_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -312,12 +368,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( 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_DeriveKeysFromSessionKey_Request( session, derivation_key, derivation_key_length, mac_key_context, mac_key_context_length, enc_key_context, enc_key_context_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -341,10 +402,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, 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_GenerateNonce_Request(session, nonce); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -369,12 +435,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( 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_PrepAndSignLicenseRequest_Request( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -401,12 +472,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( 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_PrepAndSignRenewalRequest_Request( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -426,41 +502,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t key_array_length, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_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_LoadKeys_Request( - session, message, message_length, signature, signature_length, - enc_mac_keys_iv, enc_mac_keys, key_array_length, key_array, pst, - srm_restriction_data, license_type); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_LoadKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -471,12 +512,30 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + +#ifdef OPK_PRE_HOOK_OEMCRYPTO_LOADLICENSE + result = OPK_PreHook_OEMCrypto_LoadLicense(session, message, message_length, + core_message_length, signature, + signature_length); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_PREHOOK_FAILURE; + goto cleanup_and_return; + } +#endif +#if (!defined(OPK_PRE_HOOK_OEMCRYPTO_LOADLICENSE) && \ + !defined(OPK_POST_HOOK_OEMCRYPTO_LOADLICENSE)) || \ + defined(OPK_HOOK_AND_USE_TA_OEMCRYPTO_LOADLICENSE) API_Initialize(); request = OPK_Pack_LoadLicense_Request(session, message, message_length, core_message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -485,67 +544,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); +#endif +#ifdef OPK_POST_HOOK_OEMCRYPTO_LOADLICENSE + result = OPK_PostHook_OEMCrypto_LoadLicense(session, message, message_length, + core_message_length, signature, + signature_length); - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_LoadEntitledContentKeys_Request( - session, message, message_length, key_array_length, key_array); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_POSTHOOK_FAILURE; goto cleanup_and_return; } - response = API_Transact(&request); - OPK_Unpack_LoadEntitledContentKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, size_t num_keys, - const OEMCrypto_KeyRefreshObject* key_array) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = - OPK_Pack_RefreshKeys_Request(session, message, message_length, signature, - signature_length, num_keys, key_array); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_RefreshKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } +#endif cleanup_and_return: TOS_Transport_ReleaseMessage(&request); TOS_Transport_ReleaseMessage(&response); @@ -565,12 +574,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, 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_LoadRenewal_Request(session, message, message_length, core_message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -596,12 +610,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( 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_QueryKeyControl_Request( session, content_key_id, content_key_id_length, key_control_block, key_control_block_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -620,22 +639,233 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey( - OEMCrypto_SESSION session, const uint8_t* content_key_id, - size_t content_key_id_length, OEMCryptoCipherMode cipher_mode) { +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateEntitledKeySession( + OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) { pthread_mutex_lock(&api_lock); OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); - request = OPK_Pack_SelectKey_Request(session, content_key_id, - content_key_id_length, cipher_mode); + request = OPK_Pack_CreateEntitledKeySession_Request(oec_session, key_session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); - OPK_Unpack_SelectKey_Response(&response, &result); + OPK_Unpack_CreateEntitledKeySession_Response(&response, &result, + &key_session); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_RemoveEntitledKeySession(OEMCrypto_SESSION key_session) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_RemoveEntitledKeySession_Request(key_session); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_RemoveEntitledKeySession_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_LoadEntitledContentKeys_Request( + session, message, message_length, key_array_length, key_array); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_LoadEntitledContentKeys_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = + OPK_Pack_ReassociateEntitledKeySession_Request(key_session, oec_session); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_ReassociateEntitledKeySession_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_LoadCasECMKeys_Request(session, message, message_length, + even_key, odd_key); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_LoadCasECMKeys_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session, uint8_t* key_token, + size_t* key_token_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = + OPK_Pack_GetOEMKeyToken_Request(key_session, key_token, key_token_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetOEMKeyToken_Response(&response, &result, &key_token, + &key_token_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyHandle( + OEMCrypto_SESSION session, const uint8_t* content_key_id, + size_t content_key_id_length, OEMCryptoCipherMode cipher_mode, + uint8_t* key_handle, size_t* key_handle_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_GetKeyHandle_Request(session, content_key_id, + content_key_id_length, cipher_mode, + key_handle, key_handle_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetKeyHandle_Response(&response, &result, &key_handle, + &key_handle_length); if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -650,17 +880,35 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( - OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, - size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) { + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern) { 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); + +#ifdef OPK_PRE_HOOK_OEMCRYPTO_DECRYPTCENC + result = OPK_PreHook_OEMCrypto_DecryptCENC(key_handle, key_handle_length, + samples, samples_length, pattern); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_PREHOOK_FAILURE; + goto cleanup_and_return; + } +#endif +#if (!defined(OPK_PRE_HOOK_OEMCRYPTO_DECRYPTCENC) && \ + !defined(OPK_POST_HOOK_OEMCRYPTO_DECRYPTCENC)) || \ + defined(OPK_HOOK_AND_USE_TA_OEMCRYPTO_DECRYPTCENC) API_Initialize(); - request = - OPK_Pack_DecryptCENC_Request(session, samples, samples_length, pattern); + request = OPK_Pack_DecryptCENC_Request(key_handle, key_handle_length, samples, + samples_length, pattern); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -669,6 +917,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; } +#endif +#ifdef OPK_POST_HOOK_OEMCRYPTO_DECRYPTCENC + result = OPK_PostHook_OEMCrypto_DecryptCENC(key_handle, key_handle_length, + samples, samples_length, pattern); + + if (result != OEMCrypto_SUCCESS) { + result = OPK_ERROR_POSTHOOK_FAILURE; + goto cleanup_and_return; + } +#endif cleanup_and_return: TOS_Transport_ReleaseMessage(&request); TOS_Transport_ReleaseMessage(&response); @@ -687,11 +945,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( 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_CopyBuffer_Request(session, data_addr, data_addr_length, out_buffer_descriptor, subsample_flags); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -710,18 +973,25 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, OEMCrypto_SharedMemory* out_buffer) { 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_Generic_Encrypt_Request( - session, in_buffer, in_buffer_length, iv, algorithm, out_buffer); + request = OPK_Pack_Generic_Encrypt_Request(key_handle, key_handle_length, + in_buffer, in_buffer_length, iv, + algorithm, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -741,18 +1011,25 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Decrypt( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, OEMCrypto_SharedMemory* out_buffer) { 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_Generic_Decrypt_Request( - session, in_buffer, in_buffer_length, iv, algorithm, out_buffer); + request = OPK_Pack_Generic_Decrypt_Request(key_handle, key_handle_length, + in_buffer, in_buffer_length, iv, + algorithm, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -772,18 +1049,25 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Sign( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - OEMCrypto_SharedMemory* signature, size_t* signature_length) { + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, OEMCrypto_SharedMemory* signature, + size_t* signature_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_Generic_Sign_Request( - session, buffer, buffer_length, algorithm, signature, signature_length); + request = OPK_Pack_Generic_Sign_Request(key_handle, key_handle_length, buffer, + buffer_length, algorithm, signature, + signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -803,18 +1087,25 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Verify( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, size_t signature_length) { + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + size_t signature_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_Generic_Verify_Request( - session, buffer, buffer_length, algorithm, signature, signature_length); + request = OPK_Pack_Generic_Verify_Request(key_handle, key_handle_length, + buffer, buffer_length, algorithm, + signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -840,12 +1131,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( 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_WrapKeyboxOrOEMCert_Request( keybox_or_cert, keybox_or_cert_length, wrapped_keybox_or_cert, wrapped_keybox_or_cert_length, transport_key, transport_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -871,11 +1167,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert( 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_InstallKeyboxOrOEMCert_Request(keybox_or_cert, keybox_or_cert_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -899,10 +1200,15 @@ OEMCrypto_GetProvisioningMethod(void) { OEMCrypto_ProvisioningMethod result = OEMCrypto_ProvisioningError; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_GetProvisioningMethod_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -924,10 +1230,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { 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_IsKeyboxOrOEMCertValid_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -951,10 +1262,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, 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_GetDeviceID_Request(device_id, device_id_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -979,10 +1295,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data, 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_GetKeyData_Request(key_data, key_data_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1007,10 +1328,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, 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_LoadTestKeybox_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1034,10 +1360,15 @@ OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) { 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_LoadOEMPrivateKey_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1061,11 +1392,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( 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_GetOEMPublicCertificate_Request(public_cert, public_cert_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1084,43 +1420,20 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, - size_t random_data_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_GetRandom_Request(random_data, random_data_length); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_GetRandom_Response(&response, &result, &random_data, - &random_data_length); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API uint32_t OEMCrypto_APIVersion(void) { pthread_mutex_lock(&api_lock); uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_APIVersion_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1142,10 +1455,15 @@ OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion(void) { uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_MinorAPIVersion_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1168,10 +1486,15 @@ OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length) { 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_BuildInformation_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1195,10 +1518,15 @@ OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level(void) { uint8_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_Security_Patch_Level_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1220,10 +1548,15 @@ OEMCRYPTO_API OEMCrypto_Security_Level OEMCrypto_SecurityLevel(void) { OEMCrypto_Security_Level result = OEMCrypto_Level_Unknown; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_SecurityLevel_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1246,10 +1579,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability( 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_GetHDCPCapability_Request(current, maximum); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1273,10 +1611,15 @@ OEMCrypto_GetDTCP2Capability(OEMCrypto_DTCP2_Capability* capability) { 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_GetDTCP2Capability_Request(capability); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1299,10 +1642,15 @@ OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable(void) { bool result = false; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_SupportsUsageTable_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1324,10 +1672,15 @@ OEMCRYPTO_API size_t OEMCrypto_MaximumUsageTableHeaderSize(void) { size_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_MaximumUsageTableHeaderSize_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1349,10 +1702,15 @@ OEMCRYPTO_API bool OEMCrypto_IsAntiRollbackHwPresent(void) { bool result = false; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_IsAntiRollbackHwPresent_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1374,10 +1732,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { 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_GetNumberOfOpenSessions_Request(count); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1400,10 +1763,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max) { 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_GetMaxNumberOfSessions_Request(max); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1426,10 +1794,15 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates(void) { uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_SupportedCertificates_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1452,10 +1825,15 @@ OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { 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_GetCurrentSRMVersion_Request(version); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1478,10 +1856,15 @@ OEMCRYPTO_API uint32_t OEMCrypto_GetAnalogOutputFlags(void) { uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_GetAnalogOutputFlags_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1503,10 +1886,15 @@ OEMCRYPTO_API uint32_t OEMCrypto_ResourceRatingTier(void) { uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_ResourceRatingTier_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1528,10 +1916,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ProductionReady(void) { 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_ProductionReady_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1555,10 +1948,15 @@ OEMCrypto_GetWatermarkingSupport(void) { OEMCrypto_WatermarkingSupport result = OEMCrypto_WatermarkingNotSupported; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_GetWatermarkingSupport_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1575,6 +1973,38 @@ cleanup_and_return: return result; } +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm( + OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm) { + 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_GetSignatureHashAlgorithm_Request(session, algorithm); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetSignatureHashAlgorithm_Response(&response, &result, &algorithm); + + 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_LoadProvisioning( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, @@ -1584,12 +2014,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( 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_LoadProvisioning_Request( session, message, message_length, core_message_length, signature, signature_length, wrapped_private_key, wrapped_private_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1615,11 +2050,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( 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_LoadDRMPrivateKey_Request( session, key_type, wrapped_private_key, wrapped_private_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1642,10 +2082,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey(void) { 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_LoadTestRSAKey_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1671,12 +2116,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( 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_GenerateRSASignature_Request( session, message, message_length, signature, signature_length, padding_scheme); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1702,12 +2152,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( 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_PrepAndSignProvisioningRequest_Request( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1733,11 +2188,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader( 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_CreateUsageTableHeader_Request(header_buffer, header_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1762,10 +2222,15 @@ OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) { 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_LoadUsageTableHeader_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1789,10 +2254,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry( 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_CreateNewUsageEntry_Request(session, usage_entry_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1817,10 +2287,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReuseUsageEntry( 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_ReuseUsageEntry_Request(session, usage_entry_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1845,11 +2320,16 @@ OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t usage_entry_number, 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_LoadUsageEntry_Request(session, usage_entry_number, buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1875,12 +2355,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_UpdateUsageEntry( 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_UpdateUsageEntry_Request( session, header_buffer, header_buffer_length, entry_buffer, entry_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1906,10 +2391,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeactivateUsageEntry( 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_DeactivateUsageEntry_Request(session, pst, pst_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1936,11 +2426,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, 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_ReportUsage_Request(session, pst, pst_length, buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1964,10 +2459,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, 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_MoveEntry_Request(session, new_index); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1992,11 +2492,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader( 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_ShrinkUsageTableHeader_Request( new_entry_count, header_buffer, header_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2022,11 +2527,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetBootCertificateChain( 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_GetBootCertificateChain_Request( bcc, bcc_length, additional_signature, additional_signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2055,13 +2565,18 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( 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_GenerateCertificateKeyPair_Request( session, public_key, public_key_length, public_key_signature, public_key_signature_length, wrapped_private_key, wrapped_private_key_length, key_type); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2082,15 +2597,157 @@ cleanup_and_return: return result; } +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceInformation( + uint8_t* device_info, size_t* device_info_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_GetDeviceInformation_Request(device_info, device_info_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetDeviceInformation_Response(&response, &result, &device_info, + &device_info_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceSignedCsrPayload( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + uint8_t* signed_csr_payload, size_t* signed_csr_payload_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_GetDeviceSignedCsrPayload_Request( + challenge, challenge_length, encoded_device_info, + encoded_device_info_length, signed_csr_payload, + signed_csr_payload_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetDeviceSignedCsrPayload_Response( + &response, &result, &signed_csr_payload, &signed_csr_payload_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallOemPrivateKey( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + + API_Initialize(); + request = OPK_Pack_InstallOemPrivateKey_Request( + session, key_type, wrapped_private_key, wrapped_private_key_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_InstallOemPrivateKey_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_EnterTestMode(void) { + 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_EnterTestMode_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_EnterTestMode_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash(void) { pthread_mutex_lock(&api_lock); uint32_t result = 0; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); request = OPK_Pack_SupportsDecryptHash_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2114,11 +2771,16 @@ OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, 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_SetDecryptHash_Request(session, frame_number, hash, hash_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2142,10 +2804,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHashErrorCode( 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_GetHashErrorCode_Request(session, failed_frame_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2171,11 +2838,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_AllocateSecureBuffer( 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_AllocateSecureBuffer_Request(session, buffer_size, output_descriptor, secure_fd); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2201,11 +2873,16 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_FreeSecureBuffer( 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_FreeSecureBuffer_Request(session, output_descriptor, secure_fd); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2223,93 +2900,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallOemPrivateKey( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_InstallOemPrivateKey_Request( - session, key_type, wrapped_private_key, wrapped_private_key_length); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_InstallOemPrivateKey_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = - OPK_Pack_ReassociateEntitledKeySession_Request(key_session, oec_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_ReassociateEntitledKeySession_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadCasECMKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_LoadCasECMKeys_Request(session, message, message_length, - even_key, odd_key); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_LoadCasECMKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateOTARequest(OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length, uint32_t use_test_key) { @@ -2317,11 +2907,16 @@ OEMCrypto_GenerateOTARequest(OEMCrypto_SESSION session, uint8_t* buffer, 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_GenerateOTARequest_Request(session, buffer, buffer_length, use_test_key); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2347,11 +2942,16 @@ OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session, const uint8_t* buffer, 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_ProcessOTAKeybox_Request(session, buffer, buffer_length, use_test_key); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c index 9472037..5c7a6dd 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c @@ -81,6 +81,35 @@ void OPK_Unpack_Initialize_Response(ODK_Message* msg, OEMCryptoResult* result) { } } +ODK_Message OPK_Pack_SetMaxAPIVersion_Request(uint32_t max_version) { + uint32_t api_value = 132; /* from _oecc132 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &max_version); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_SetMaxAPIVersion_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 132) + 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_Terminate_Request(void) { uint32_t api_value = 2; /* from _oecc2 */ ODK_Message msg = TOS_Transport_GetRequest(); @@ -224,69 +253,6 @@ void OPK_Unpack_CloseSession_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_CreateEntitledKeySession_Request( - OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session) { - uint32_t api_value = 111; /* from _oecc111 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &oec_session); - OPK_PackIsNull(&msg, key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_CreateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result, - OEMCrypto_SESSION** key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 111) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackNullable_uint32_t(msg, key_session); - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( - OEMCrypto_SESSION key_session) { - uint32_t api_value = 112; /* from _oecc112 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 112) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_GenerateDerivedKeys_Request( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -520,64 +486,6 @@ void OPK_Unpack_PrepAndSignRenewalRequest_Response( } } -ODK_Message OPK_Pack_LoadKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t key_array_length, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type) { - uint32_t api_value = 83; /* from _oecc83 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_size_t(&msg, &signature_length); - OPK_Pack_size_t(&msg, &key_array_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - OPK_PackMemory(&msg, (const uint8_t*)signature, - OPK_ToLengthType(signature_length)); - OPK_Pack_OEMCrypto_Substring(&msg, &enc_mac_keys_iv); - OPK_Pack_OEMCrypto_Substring(&msg, &enc_mac_keys); - /* pack object array with packer function OPK_Pack_OEMCrypto_KeyObject */ - ODK_Message* const odk_message = &msg; - const void* const objs = (const void*)key_array; - const LengthType count = OPK_ToLengthType(key_array_length); - const size_t size = sizeof(OEMCrypto_KeyObject); - const bool is_null = objs == NULL || OPK_LengthIsNull(count); - if (!OPK_PackBoolValue(odk_message, is_null)) { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Pack_OEMCrypto_KeyObject( - odk_message, (const OEMCrypto_KeyObject*)(objs + i * size)); - } - } - OPK_Pack_OEMCrypto_Substring(&msg, &pst); - OPK_Pack_OEMCrypto_Substring(&msg, &srm_restriction_data); - OPK_Pack_uint32_t(&msg, &license_type); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadKeys_Response(ODK_Message* msg, OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 83) - 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_LoadLicense_Request(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -619,96 +527,6 @@ void OPK_Unpack_LoadLicense_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - uint32_t api_value = 121; /* from _oecc121 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_size_t(&msg, &key_array_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - /* pack object array with packer function - * OPK_Pack_OEMCrypto_EntitledContentKeyObject */ - ODK_Message* const odk_message = &msg; - const void* const objs = (const void*)key_array; - const LengthType count = OPK_ToLengthType(key_array_length); - const size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); - const bool is_null = objs == NULL || OPK_LengthIsNull(count); - if (!OPK_PackBoolValue(odk_message, is_null)) { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Pack_OEMCrypto_EntitledContentKeyObject( - odk_message, - (const OEMCrypto_EntitledContentKeyObject*)(objs + i * size)); - } - } - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 121) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_RefreshKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, size_t num_keys, - const OEMCrypto_KeyRefreshObject* key_array) { - uint32_t api_value = 91; /* from _oecc91 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_size_t(&msg, &signature_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - OPK_PackMemory(&msg, (const uint8_t*)signature, - OPK_ToLengthType(signature_length)); - OPK_Pack_size_t(&msg, &num_keys); - OPK_PackNullable_OEMCrypto_KeyRefreshObject(&msg, key_array); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RefreshKeys_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 91) - 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_LoadRenewal_Request(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -798,29 +616,57 @@ void OPK_Unpack_QueryKeyControl_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_SelectKey_Request(OEMCrypto_SESSION session, - const uint8_t* content_key_id, - size_t content_key_id_length, - OEMCryptoCipherMode cipher_mode) { - uint32_t api_value = 81; /* from _oecc81 */ +ODK_Message OPK_Pack_CreateEntitledKeySession_Request( + OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session) { + uint32_t api_value = 111; /* from _oecc111 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &content_key_id_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)content_key_id, - OPK_ToLengthType(content_key_id_length)); - OPK_Pack_uint32_t(&msg, &cipher_mode); + OPK_Pack_uint32_t(&msg, &oec_session); + OPK_PackIsNull(&msg, key_session); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); return msg; } -void OPK_Unpack_SelectKey_Response(ODK_Message* msg, OEMCryptoResult* result) { +void OPK_Unpack_CreateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SESSION** key_session) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 81) + if (api_value != 111) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_uint32_t(msg, key_session); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( + OEMCrypto_SESSION key_session) { + uint32_t api_value = 112; /* from _oecc112 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 112) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -833,16 +679,230 @@ void OPK_Unpack_SelectKey_Response(ODK_Message* msg, OEMCryptoResult* result) { } } -ODK_Message OPK_Pack_DecryptCENC_Request( - OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, - size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) { - uint32_t api_value = 105; /* from _oecc105 */ +ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + uint32_t api_value = 121; /* from _oecc121 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &samples_length); + OPK_Pack_size_t(&msg, &message_length); + OPK_Pack_size_t(&msg, &key_array_length); OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)message, + OPK_ToLengthType(message_length)); + /* pack object array with packer function + * OPK_Pack_OEMCrypto_EntitledContentKeyObject */ + ODK_Message* const odk_message = &msg; + const void* const objs = (const void*)key_array; + const LengthType count = OPK_ToLengthType(key_array_length); + const size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); + const bool is_null = objs == NULL || OPK_LengthIsNull(count); + if (!OPK_PackBoolValue(odk_message, is_null)) { + for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + const uint8_t* new_address = (const uint8_t*)objs + i * size; + OPK_Pack_OEMCrypto_EntitledContentKeyObject( + odk_message, + (const OEMCrypto_EntitledContentKeyObject*)(const void*)new_address); + } + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 121) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { + uint32_t api_value = 119; /* from _oecc119 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_Pack_uint32_t(&msg, &oec_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ReassociateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 119) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_LoadCasECMKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key) { + uint32_t api_value = 120; /* from _oecc120 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &message_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)message, + OPK_ToLengthType(message_length)); + OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, even_key); + OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, odd_key); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 120) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetOEMKeyToken_Request(OEMCrypto_SESSION key_session, + const uint8_t* key_token, + const size_t* key_token_length) { + uint32_t api_value = 130; /* from _oecc130 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackNullable_size_t(&msg, key_token_length); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_PackAlloc(&msg, key_token); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetOEMKeyToken_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** key_token, + size_t** key_token_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 130) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, key_token_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(key_token_length)); + if (p && *key_token) { + memcpy(*key_token, p, OPK_SafeDerefSizeTPtrPtr(key_token_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetKeyHandle_Request(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, + const uint8_t* key_handle, + const size_t* key_handle_length) { + uint32_t api_value = 133; /* from _oecc133 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &content_key_id_length); + OPK_PackNullable_size_t(&msg, key_handle_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)content_key_id, + OPK_ToLengthType(content_key_id_length)); + OPK_Pack_uint32_t(&msg, &cipher_mode); + OPK_PackAlloc(&msg, key_handle); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetKeyHandle_Response(ODK_Message* msg, OEMCryptoResult* result, + uint8_t** key_handle, + size_t** key_handle_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 133) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, key_handle_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(key_handle_length)); + if (p && *key_handle) { + memcpy(*key_handle, p, OPK_SafeDerefSizeTPtrPtr(key_handle_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_DecryptCENC_Request( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern) { + uint32_t api_value = 134; /* from _oecc134 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &key_handle_length); + OPK_Pack_size_t(&msg, &samples_length); + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_ToLengthType(key_handle_length)); /* pack object array with packer function OPK_Pack_OEMCrypto_SampleDescription */ ODK_Message* const odk_message = &msg; @@ -852,8 +912,10 @@ ODK_Message OPK_Pack_DecryptCENC_Request( const bool is_null = objs == NULL || OPK_LengthIsNull(count); if (!OPK_PackBoolValue(odk_message, is_null)) { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + const uint8_t* new_address = (const uint8_t*)objs + i * size; OPK_Pack_OEMCrypto_SampleDescription( - odk_message, (const OEMCrypto_SampleDescription*)(objs + i * size)); + odk_message, + (const OEMCrypto_SampleDescription*)(const void*)new_address); } } OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc(&msg, pattern); @@ -866,7 +928,7 @@ void OPK_Unpack_DecryptCENC_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 105) + if (api_value != 134) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -918,20 +980,23 @@ void OPK_Unpack_CopyBuffer_Response(ODK_Message* msg, OEMCryptoResult* result) { } ODK_Message OPK_Pack_Generic_Encrypt_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* out_buffer) { - uint32_t api_value = 24; /* from _oecc24 */ + uint32_t api_value = 135; /* from _oecc135 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &key_handle_length); OPK_Pack_size_t(&msg, &in_buffer_length); - OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_ToLengthType(key_handle_length)); OPK_PackSharedBuffer(&msg, in_buffer, OPK_ToLengthType(in_buffer_length), /* map */ true, /* copy_in */ true, /* is_output */ false); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_Pack_uint32_t(&msg, &algorithm); OPK_PackSharedBuffer(&msg, out_buffer, OPK_ToLengthType(in_buffer_length), /* map */ true, /* copy_in */ false, @@ -947,7 +1012,7 @@ void OPK_Unpack_Generic_Encrypt_Response(ODK_Message* msg, OEMCrypto_SharedMemory** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 24) + if (api_value != 135) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, in_buffer_length); OPK_Unpack_uint32_t(msg, result); @@ -966,20 +1031,23 @@ void OPK_Unpack_Generic_Encrypt_Response(ODK_Message* msg, } ODK_Message OPK_Pack_Generic_Decrypt_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* out_buffer) { - uint32_t api_value = 25; /* from _oecc25 */ + uint32_t api_value = 136; /* from _oecc136 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &key_handle_length); OPK_Pack_size_t(&msg, &in_buffer_length); - OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_ToLengthType(key_handle_length)); OPK_PackSharedBuffer(&msg, in_buffer, OPK_ToLengthType(in_buffer_length), /* map */ true, /* copy_in */ true, /* is_output */ false); - OPK_PackArray(&msg, &iv[0], 16); + OPK_PackMemory(&msg, (const uint8_t*)iv, OPK_ToLengthType(16)); OPK_Pack_uint32_t(&msg, &algorithm); OPK_PackSharedBuffer(&msg, out_buffer, OPK_ToLengthType(in_buffer_length), /* map */ true, /* copy_in */ false, @@ -995,7 +1063,7 @@ void OPK_Unpack_Generic_Decrypt_Response(ODK_Message* msg, OEMCrypto_SharedMemory** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 25) + if (api_value != 136) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, in_buffer_length); OPK_Unpack_uint32_t(msg, result); @@ -1014,17 +1082,20 @@ void OPK_Unpack_Generic_Decrypt_Response(ODK_Message* msg, } ODK_Message OPK_Pack_Generic_Sign_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, const size_t* signature_length) { - uint32_t api_value = 26; /* from _oecc26 */ + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + const size_t* signature_length) { + uint32_t api_value = 137; /* from _oecc137 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &key_handle_length); OPK_Pack_size_t(&msg, &buffer_length); OPK_PackNullable_size_t(&msg, signature_length); - OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_ToLengthType(key_handle_length)); OPK_PackSharedBuffer(&msg, buffer, OPK_ToLengthType(buffer_length), /* map */ true, /* copy_in */ true, /* is_output */ false); @@ -1042,7 +1113,7 @@ void OPK_Unpack_Generic_Sign_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 26) + if (api_value != 137) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -1062,17 +1133,20 @@ void OPK_Unpack_Generic_Sign_Response(ODK_Message* msg, OEMCryptoResult* result, } ODK_Message OPK_Pack_Generic_Verify_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, size_t signature_length) { - uint32_t api_value = 27; /* from _oecc27 */ + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + size_t signature_length) { + uint32_t api_value = 138; /* from _oecc138 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &key_handle_length); OPK_Pack_size_t(&msg, &buffer_length); OPK_Pack_size_t(&msg, &signature_length); - OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_ToLengthType(key_handle_length)); OPK_PackSharedBuffer(&msg, buffer, OPK_ToLengthType(buffer_length), /* map */ true, /* copy_in */ true, /* is_output */ false); @@ -1089,7 +1163,7 @@ void OPK_Unpack_Generic_Verify_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 27) + if (api_value != 138) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1419,46 +1493,6 @@ void OPK_Unpack_GetOEMPublicCertificate_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_GetRandom_Request(const uint8_t* random_data, - size_t random_data_length) { - uint32_t api_value = 6; /* from _oecc6 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &random_data_length); - OPK_PackAlloc(&msg, random_data); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_GetRandom_Response(ODK_Message* msg, OEMCryptoResult* result, - uint8_t** random_data, - size_t* random_data_length) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 6) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_size_t(msg, random_data_length); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - if (SuccessResult(*result)) { - uint8_t* p; - OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtr(random_data_length)); - if (p && *random_data) { - memcpy(*random_data, p, OPK_SafeDerefSizeTPtr(random_data_length)); - } - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_APIVersion_Request(void) { uint32_t api_value = 22; /* from _oecc22 */ ODK_Message msg = TOS_Transport_GetRequest(); @@ -1948,6 +1982,45 @@ void OPK_Unpack_GetWatermarkingSupport_Response( OPK_SharedBuffer_FinalizeUnpacking(); } +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Request( + OEMCrypto_SESSION session, + const OEMCrypto_SignatureHashAlgorithm* algorithm) { + uint32_t api_value = 139; /* from _oecc139 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &session); + OPK_PackIsNull(&msg, algorithm); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetSignatureHashAlgorithm_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SignatureHashAlgorithm** algorithm) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 139) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_uint32_t(msg, algorithm); + if (*algorithm) { + if (!Is_Valid_OEMCrypto_SignatureHashAlgorithm(**algorithm)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_LoadProvisioning_Request( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, @@ -2678,6 +2751,160 @@ void OPK_Unpack_GenerateCertificateKeyPair_Response( } } +ODK_Message OPK_Pack_GetDeviceInformation_Request( + const uint8_t* device_info, const size_t* device_info_length) { + uint32_t api_value = 131; /* from _oecc131 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackNullable_size_t(&msg, device_info_length); + OPK_PackAlloc(&msg, device_info); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceInformation_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** device_info, + size_t** device_info_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 131) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, device_info_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(device_info_length)); + if (p && *device_info) { + memcpy(*device_info, p, OPK_SafeDerefSizeTPtrPtr(device_info_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetDeviceSignedCsrPayload_Request( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length) { + uint32_t api_value = 141; /* from _oecc141 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &challenge_length); + OPK_Pack_size_t(&msg, &encoded_device_info_length); + OPK_PackNullable_size_t(&msg, signed_csr_payload_length); + OPK_PackMemory(&msg, (const uint8_t*)challenge, + OPK_ToLengthType(challenge_length)); + OPK_PackMemory(&msg, (const uint8_t*)encoded_device_info, + OPK_ToLengthType(encoded_device_info_length)); + OPK_PackAlloc(&msg, signed_csr_payload); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceSignedCsrPayload_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** signed_csr_payload, + size_t** signed_csr_payload_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 141) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, signed_csr_payload_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(signed_csr_payload_length)); + if (p && *signed_csr_payload) { + memcpy(*signed_csr_payload, p, + OPK_SafeDerefSizeTPtrPtr(signed_csr_payload_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_InstallOemPrivateKey_Request( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { + uint32_t api_value = 118; /* from _oecc118 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &wrapped_private_key_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_Pack_uint32_t(&msg, &key_type); + OPK_PackMemory(&msg, (const uint8_t*)wrapped_private_key, + OPK_ToLengthType(wrapped_private_key_length)); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 118) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_EnterTestMode_Request(void) { + uint32_t api_value = 140; /* from _oecc140 */ + 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_EnterTestMode_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 140) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_SupportsDecryptHash_Request(void) { uint32_t api_value = 86; /* from _oecc86 */ ODK_Message msg = TOS_Transport_GetRequest(); @@ -2840,109 +3067,6 @@ void OPK_Unpack_FreeSecureBuffer_Response( } } -ODK_Message OPK_Pack_InstallOemPrivateKey_Request( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { - uint32_t api_value = 118; /* from _oecc118 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &wrapped_private_key_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_Pack_uint32_t(&msg, &key_type); - OPK_PackMemory(&msg, (const uint8_t*)wrapped_private_key, - OPK_ToLengthType(wrapped_private_key_length)); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 118) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { - uint32_t api_value = 119; /* from _oecc119 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &key_session); - OPK_Pack_uint32_t(&msg, &oec_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_ReassociateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 119) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_LoadCasECMKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key) { - uint32_t api_value = 120; /* from _oecc120 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, even_key); - OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, odd_key); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 120) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_OPK_SerializationVersion_Request( const uint32_t* ree_major, const uint32_t* ree_minor, const uint32_t* tee_major, const uint32_t* tee_minor) { diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h index 147658c..2535ed9 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h @@ -22,6 +22,9 @@ ODK_Message OPK_Pack_SetSandbox_Request(const uint8_t* sandbox_id, void OPK_Unpack_SetSandbox_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_Initialize_Request(void); void OPK_Unpack_Initialize_Response(ODK_Message* msg, OEMCryptoResult* result); +ODK_Message OPK_Pack_SetMaxAPIVersion_Request(uint32_t max_version); +void OPK_Unpack_SetMaxAPIVersion_Response(ODK_Message* msg, + OEMCryptoResult* result); ODK_Message OPK_Pack_Terminate_Request(void); void OPK_Unpack_Terminate_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_Idle_Request(OEMCrypto_IdleState state, @@ -35,14 +38,6 @@ void OPK_Unpack_OpenSession_Response(ODK_Message* msg, OEMCryptoResult* result, ODK_Message OPK_Pack_CloseSession_Request(OEMCrypto_SESSION session); void OPK_Unpack_CloseSession_Response(ODK_Message* msg, OEMCryptoResult* result); -ODK_Message OPK_Pack_CreateEntitledKeySession_Request( - OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session); -void OPK_Unpack_CreateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_SESSION** key_session); -ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( - OEMCrypto_SESSION key_session); -void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result); ODK_Message OPK_Pack_GenerateDerivedKeys_Request( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -79,14 +74,6 @@ void OPK_Unpack_PrepAndSignRenewalRequest_Response( ODK_Message* msg, OEMCryptoResult* result, uint8_t** message, size_t* message_length, size_t** core_message_size, uint8_t** signature, size_t** signature_length); -ODK_Message OPK_Pack_LoadKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t key_array_length, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type); -void OPK_Unpack_LoadKeys_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_LoadLicense_Request(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -94,17 +81,6 @@ ODK_Message OPK_Pack_LoadLicense_Request(OEMCrypto_SESSION session, const uint8_t* signature, size_t signature_length); void OPK_Unpack_LoadLicense_Response(ODK_Message* msg, OEMCryptoResult* result); -ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array); -void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, - OEMCryptoResult* result); -ODK_Message OPK_Pack_RefreshKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, size_t num_keys, - const OEMCrypto_KeyRefreshObject* key_array); -void OPK_Unpack_RefreshKeys_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_LoadRenewal_Request(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -120,14 +96,50 @@ void OPK_Unpack_QueryKeyControl_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** key_control_block, size_t** key_control_block_length); -ODK_Message OPK_Pack_SelectKey_Request(OEMCrypto_SESSION session, - const uint8_t* content_key_id, - size_t content_key_id_length, - OEMCryptoCipherMode cipher_mode); -void OPK_Unpack_SelectKey_Response(ODK_Message* msg, OEMCryptoResult* result); +ODK_Message OPK_Pack_CreateEntitledKeySession_Request( + OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session); +void OPK_Unpack_CreateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_SESSION** key_session); +ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( + OEMCrypto_SESSION key_session); +void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); +void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); +void OPK_Unpack_ReassociateEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_LoadCasECMKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); +void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_GetOEMKeyToken_Request(OEMCrypto_SESSION key_session, + const uint8_t* key_token, + const size_t* key_token_length); +void OPK_Unpack_GetOEMKeyToken_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** key_token, + size_t** key_token_length); +ODK_Message OPK_Pack_GetKeyHandle_Request(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, + const uint8_t* key_handle, + const size_t* key_handle_length); +void OPK_Unpack_GetKeyHandle_Response(ODK_Message* msg, OEMCryptoResult* result, + uint8_t** key_handle, + size_t** key_handle_length); ODK_Message OPK_Pack_DecryptCENC_Request( - OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, - size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern); + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern); void OPK_Unpack_DecryptCENC_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_CopyBuffer_Request( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* data_addr, @@ -136,32 +148,36 @@ ODK_Message OPK_Pack_CopyBuffer_Request( uint8_t subsample_flags); void OPK_Unpack_CopyBuffer_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_Generic_Encrypt_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* out_buffer); void OPK_Unpack_Generic_Encrypt_Response(ODK_Message* msg, OEMCryptoResult* result, size_t* in_buffer_length, OEMCrypto_SharedMemory** out_buffer); ODK_Message OPK_Pack_Generic_Decrypt_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, - size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, size_t in_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* out_buffer); void OPK_Unpack_Generic_Decrypt_Response(ODK_Message* msg, OEMCryptoResult* result, size_t* in_buffer_length, OEMCrypto_SharedMemory** out_buffer); ODK_Message OPK_Pack_Generic_Sign_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, const size_t* signature_length); + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + const size_t* signature_length); void OPK_Unpack_Generic_Sign_Response(ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_SharedMemory** signature, size_t** signature_length); ODK_Message OPK_Pack_Generic_Verify_Request( - OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const OEMCrypto_SharedMemory* signature, size_t signature_length); + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, size_t buffer_length, + OEMCrypto_Algorithm algorithm, const OEMCrypto_SharedMemory* signature, + size_t signature_length); void OPK_Unpack_Generic_Verify_Response(ODK_Message* msg, OEMCryptoResult* result); ODK_Message OPK_Pack_WrapKeyboxOrOEMCert_Request( @@ -205,11 +221,6 @@ void OPK_Unpack_GetOEMPublicCertificate_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** public_cert, size_t** public_cert_length); -ODK_Message OPK_Pack_GetRandom_Request(const uint8_t* random_data, - size_t random_data_length); -void OPK_Unpack_GetRandom_Response(ODK_Message* msg, OEMCryptoResult* result, - uint8_t** random_data, - size_t* random_data_length); ODK_Message OPK_Pack_APIVersion_Request(void); void OPK_Unpack_APIVersion_Response(ODK_Message* msg, uint32_t* result); ODK_Message OPK_Pack_MinorAPIVersion_Request(void); @@ -272,6 +283,12 @@ void OPK_Unpack_ProductionReady_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetWatermarkingSupport_Request(void); void OPK_Unpack_GetWatermarkingSupport_Response( ODK_Message* msg, OEMCrypto_WatermarkingSupport* result); +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Request( + OEMCrypto_SESSION session, + const OEMCrypto_SignatureHashAlgorithm* algorithm); +void OPK_Unpack_GetSignatureHashAlgorithm_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SignatureHashAlgorithm** algorithm); ODK_Message OPK_Pack_LoadProvisioning_Request( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, @@ -380,6 +397,27 @@ void OPK_Unpack_GenerateCertificateKeyPair_Response( size_t** public_key_length, uint8_t** public_key_signature, size_t** public_key_signature_length, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, OEMCrypto_PrivateKeyType** key_type); +ODK_Message OPK_Pack_GetDeviceInformation_Request( + const uint8_t* device_info, const size_t* device_info_length); +void OPK_Unpack_GetDeviceInformation_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** device_info, + size_t** device_info_length); +ODK_Message OPK_Pack_GetDeviceSignedCsrPayload_Request( + const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, size_t encoded_device_info_length, + const uint8_t* signed_csr_payload, const size_t* signed_csr_payload_length); +void OPK_Unpack_GetDeviceSignedCsrPayload_Response( + ODK_Message* msg, OEMCryptoResult* result, uint8_t** signed_csr_payload, + size_t** signed_csr_payload_length); +ODK_Message OPK_Pack_InstallOemPrivateKey_Request( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); +void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_EnterTestMode_Request(void); +void OPK_Unpack_EnterTestMode_Response(ODK_Message* msg, + OEMCryptoResult* result); ODK_Message OPK_Pack_SupportsDecryptHash_Request(void); void OPK_Unpack_SupportsDecryptHash_Response(ODK_Message* msg, uint32_t* result); @@ -406,21 +444,6 @@ ODK_Message OPK_Pack_FreeSecureBuffer_Request( void OPK_Unpack_FreeSecureBuffer_Response( ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_DestBufferDesc** output_descriptor); -ODK_Message OPK_Pack_InstallOemPrivateKey_Request( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); -void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, - OEMCryptoResult* result); -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); -void OPK_Unpack_ReassociateEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result); -ODK_Message OPK_Pack_LoadCasECMKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key); -void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, - OEMCryptoResult* result); ODK_Message OPK_Pack_OPK_SerializationVersion_Request( const uint32_t* ree_major, const uint32_t* ree_minor, const uint32_t* tee_major, const uint32_t* tee_minor); diff --git a/oemcrypto/opk/serialization/ree/ree_special_cases.c b/oemcrypto/opk/serialization/ree/ree_special_cases.c index 434d5db..fc7d976 100644 --- a/oemcrypto/opk/serialization/ree/ree_special_cases.c +++ b/oemcrypto/opk/serialization/ree/ree_special_cases.c @@ -74,3 +74,5 @@ void OPK_Pack_RewrapDeviceRSAKey_Request( OPK_PackEOM(msg); OPK_SharedBuffer_FinalizePacking(); } + +OEMCryptoResult OPK_PreHook_OEMCrypto_Initialize(void) { return 0; } diff --git a/oemcrypto/opk/serialization/ree/ree_special_cases.h b/oemcrypto/opk/serialization/ree/ree_special_cases.h index cb3580c..b2b22a4 100644 --- a/oemcrypto/opk/serialization/ree/ree_special_cases.h +++ b/oemcrypto/opk/serialization/ree/ree_special_cases.h @@ -28,6 +28,36 @@ void OPK_Pack_RewrapDeviceRSAKey_Request( size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, const uint8_t* wrapped_rsa_key, const size_t* wrapped_rsa_key_length); +/* + * Optional function declarations for custom REE-side hooks. See + * GEN_oemcrypto_api.c for usage. If not using custom hooks, definitions for + * these functions are not required. + */ +OEMCryptoResult OPK_PreHook_OEMCrypto_Initialize(void); +OEMCryptoResult OPK_PostHook_OEMCrypto_Initialize(void); +OEMCryptoResult OPK_PreHook_OEMCrypto_Terminate(void); +OEMCryptoResult OPK_PostHook_OEMCrypto_Terminate(void); +OEMCryptoResult OPK_PreHook_OEMCrypto_DecryptCENC( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern); +OEMCryptoResult OPK_PostHook_OEMCrypto_DecryptCENC( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern); +OEMCryptoResult OPK_PreHook_OEMCrypto_LoadLicense(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + size_t core_message_length, + const uint8_t* signature, + size_t signature_length); +OEMCryptoResult OPK_PostHook_OEMCrypto_LoadLicense(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + size_t core_message_length, + const uint8_t* signature, + size_t signature_length); + #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/serialization/settings.gypi b/oemcrypto/opk/serialization/settings.gypi index c2a970f..f3667ee 100644 --- a/oemcrypto/opk/serialization/settings.gypi +++ b/oemcrypto/opk/serialization/settings.gypi @@ -12,6 +12,7 @@ 'tee_dir' : '<(serialization_dir)/tee', 'third_party_dir' : '<(DEPTH)/third_party', 'json_dir' : '<(third_party_dir)/nlohmann-json', + 'jsmn_dir' : '<(third_party_dir)/jsmn', 'enable_message_debug' : 'cipher_mode); } -void OPK_Init_OEMCrypto_KeyRefreshObject(OEMCrypto_KeyRefreshObject* obj) { - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_id); - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control_iv); - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control); -} - void OPK_Init_OEMCrypto_CENCEncryptPatternDesc_V15( OEMCrypto_CENCEncryptPatternDesc_V15* obj) { OPK_Init_size_t((size_t*)&obj->encrypt); @@ -151,6 +145,12 @@ void OPK_Init_OEMCrypto_EntitledContentKeyObject_V16( OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->content_key_data); } +void OPK_Init_OEMCrypto_KeyRefreshObject(OEMCrypto_KeyRefreshObject* obj) { + OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_id); + OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control_iv); + OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control); +} + /* See opk_dispatcher.h for definition of OPK_DispatchMessage() */ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, ODK_Message* response) { @@ -192,6 +192,19 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Initialize_Response(result); break; } + case 132: /* OEMCrypto_SetMaxAPIVersion */ + { + uint32_t max_version; + OPK_Init_uint32_t((uint32_t*)&max_version); + OPK_Unpack_SetMaxAPIVersion_Request(request, &max_version); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("SetMaxAPIVersion"); + result = OEMCrypto_SetMaxAPIVersion(max_version); + *response = OPK_Pack_SetMaxAPIVersion_Response(result); + break; + } case 2: /* OEMCrypto_Terminate */ { OPK_Unpack_Terminate_Request(request); @@ -255,36 +268,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_CloseSession_Response(result); break; } - case 111: /* OEMCrypto_CreateEntitledKeySession */ - { - OEMCrypto_SESSION oec_session; - OPK_Init_uint32_t((uint32_t*)&oec_session); - OEMCrypto_SESSION* key_session; - OPK_InitPointer((uint8_t**)&key_session); - OPK_Unpack_CreateEntitledKeySession_Request(request, &oec_session, - &key_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("CreateEntitledKeySession"); - result = OEMCrypto_CreateEntitledKeySession(oec_session, key_session); - *response = - OPK_Pack_CreateEntitledKeySession_Response(result, key_session); - break; - } - case 112: /* OEMCrypto_RemoveEntitledKeySession */ - { - OEMCrypto_SESSION key_session; - OPK_Init_uint32_t((uint32_t*)&key_session); - OPK_Unpack_RemoveEntitledKeySession_Request(request, &key_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("RemoveEntitledKeySession"); - result = OEMCrypto_RemoveEntitledKeySession(key_session); - *response = OPK_Pack_RemoveEntitledKeySession_Response(result); - break; - } case 95: /* OEMCrypto_GenerateDerivedKeys */ { size_t mac_key_context_length; @@ -413,47 +396,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, signature_length); break; } - case 83: /* OEMCrypto_LoadKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - size_t signature_length; - OPK_Init_size_t((size_t*)&signature_length); - size_t key_array_length; - OPK_Init_size_t((size_t*)&key_array_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - uint8_t* signature; - OPK_InitPointer((uint8_t**)&signature); - OEMCrypto_Substring enc_mac_keys_iv; - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&enc_mac_keys_iv); - OEMCrypto_Substring enc_mac_keys; - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&enc_mac_keys); - OEMCrypto_KeyObject* key_array; - OPK_InitPointer((uint8_t**)&key_array); - OEMCrypto_Substring pst; - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&pst); - OEMCrypto_Substring srm_restriction_data; - OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&srm_restriction_data); - OEMCrypto_LicenseType license_type; - OPK_Init_uint32_t((uint32_t*)&license_type); - OPK_Unpack_LoadKeys_Request( - request, &session, &message, &message_length, &signature, - &signature_length, &enc_mac_keys_iv, &enc_mac_keys, &key_array_length, - &key_array, &pst, &srm_restriction_data, &license_type); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("LoadKeys"); - result = OEMCrypto_LoadKeys(session, message, message_length, signature, - signature_length, enc_mac_keys_iv, - enc_mac_keys, key_array_length, key_array, - pst, srm_restriction_data, license_type); - *response = OPK_Pack_LoadKeys_Response(result); - break; - } case 99: /* OEMCrypto_LoadLicense */ { size_t message_length; @@ -481,62 +423,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_LoadLicense_Response(result); break; } - case 121: /* OEMCrypto_LoadEntitledContentKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - size_t key_array_length; - OPK_Init_size_t((size_t*)&key_array_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - OEMCrypto_EntitledContentKeyObject* key_array; - OPK_InitPointer((uint8_t**)&key_array); - OPK_Unpack_LoadEntitledContentKeys_Request(request, &session, &message, - &message_length, - &key_array_length, &key_array); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("LoadEntitledContentKeys"); - result = OEMCrypto_LoadEntitledContentKeys( - session, message, message_length, key_array_length, key_array); - *response = OPK_Pack_LoadEntitledContentKeys_Response(result); - break; - } - case 91: /* OEMCrypto_RefreshKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - size_t signature_length; - OPK_Init_size_t((size_t*)&signature_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - uint8_t* signature; - OPK_InitPointer((uint8_t**)&signature); - size_t num_keys; - OPK_Init_size_t((size_t*)&num_keys); - OEMCrypto_KeyRefreshObject* key_array = - (OEMCrypto_KeyRefreshObject*)OPK_VarAlloc( - sizeof(OEMCrypto_KeyRefreshObject)); - OPK_Init_OEMCrypto_KeyRefreshObject( - (OEMCrypto_KeyRefreshObject*)key_array); - OPK_Unpack_RefreshKeys_Request(request, &session, &message, - &message_length, &signature, - &signature_length, &num_keys, &key_array); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("RefreshKeys"); - result = - OEMCrypto_RefreshKeys(session, message, message_length, signature, - signature_length, num_keys, key_array); - *response = OPK_Pack_RefreshKeys_Response(result); - break; - } case 101: /* OEMCrypto_LoadRenewal */ { size_t message_length; @@ -590,32 +476,162 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, key_control_block_length); break; } - case 81: /* OEMCrypto_SelectKey */ + case 111: /* OEMCrypto_CreateEntitledKeySession */ + { + OEMCrypto_SESSION oec_session; + OPK_Init_uint32_t((uint32_t*)&oec_session); + OEMCrypto_SESSION* key_session; + OPK_InitPointer((uint8_t**)&key_session); + OPK_Unpack_CreateEntitledKeySession_Request(request, &oec_session, + &key_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("CreateEntitledKeySession"); + result = OEMCrypto_CreateEntitledKeySession(oec_session, key_session); + *response = + OPK_Pack_CreateEntitledKeySession_Response(result, key_session); + break; + } + case 112: /* OEMCrypto_RemoveEntitledKeySession */ + { + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + OPK_Unpack_RemoveEntitledKeySession_Request(request, &key_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("RemoveEntitledKeySession"); + result = OEMCrypto_RemoveEntitledKeySession(key_session); + *response = OPK_Pack_RemoveEntitledKeySession_Response(result); + break; + } + case 121: /* OEMCrypto_LoadEntitledContentKeys */ + { + size_t message_length; + OPK_Init_size_t((size_t*)&message_length); + size_t key_array_length; + OPK_Init_size_t((size_t*)&key_array_length); + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* message; + OPK_InitPointer((uint8_t**)&message); + OEMCrypto_EntitledContentKeyObject* key_array; + OPK_InitPointer((uint8_t**)&key_array); + OPK_Unpack_LoadEntitledContentKeys_Request(request, &session, &message, + &message_length, + &key_array_length, &key_array); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("LoadEntitledContentKeys"); + result = OEMCrypto_LoadEntitledContentKeys( + session, message, message_length, key_array_length, key_array); + *response = OPK_Pack_LoadEntitledContentKeys_Response(result); + break; + } + case 119: /* OEMCrypto_ReassociateEntitledKeySession */ + { + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + OEMCrypto_SESSION oec_session; + OPK_Init_uint32_t((uint32_t*)&oec_session); + OPK_Unpack_ReassociateEntitledKeySession_Request(request, &key_session, + &oec_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("ReassociateEntitledKeySession"); + result = + OEMCrypto_ReassociateEntitledKeySession(key_session, oec_session); + *response = OPK_Pack_ReassociateEntitledKeySession_Response(result); + break; + } + case 120: /* OEMCrypto_LoadCasECMKeys */ + { + size_t message_length; + OPK_Init_size_t((size_t*)&message_length); + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* message; + OPK_InitPointer((uint8_t**)&message); + OEMCrypto_EntitledContentKeyObject* even_key = + (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( + sizeof(OEMCrypto_EntitledContentKeyObject)); + OPK_Init_OEMCrypto_EntitledContentKeyObject( + (OEMCrypto_EntitledContentKeyObject*)even_key); + OEMCrypto_EntitledContentKeyObject* odd_key = + (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( + sizeof(OEMCrypto_EntitledContentKeyObject)); + OPK_Init_OEMCrypto_EntitledContentKeyObject( + (OEMCrypto_EntitledContentKeyObject*)odd_key); + OPK_Unpack_LoadCasECMKeys_Request(request, &session, &message, + &message_length, &even_key, &odd_key); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("LoadCasECMKeys"); + result = OEMCrypto_LoadCasECMKeys(session, message, message_length, + even_key, odd_key); + *response = OPK_Pack_LoadCasECMKeys_Response(result); + break; + } + case 130: /* OEMCrypto_GetOEMKeyToken */ + { + size_t* key_token_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(key_token_length); + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + uint8_t* key_token; + OPK_InitPointer((uint8_t**)&key_token); + OPK_Unpack_GetOEMKeyToken_Request(request, &key_session, &key_token, + &key_token_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetOEMKeyToken"); + result = + OEMCrypto_GetOEMKeyToken(key_session, key_token, key_token_length); + *response = + OPK_Pack_GetOEMKeyToken_Response(result, key_token, key_token_length); + break; + } + case 133: /* OEMCrypto_GetKeyHandle */ { size_t content_key_id_length; OPK_Init_size_t((size_t*)&content_key_id_length); + size_t* key_handle_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(key_handle_length); OEMCrypto_SESSION session; OPK_Init_uint32_t((uint32_t*)&session); uint8_t* content_key_id; OPK_InitPointer((uint8_t**)&content_key_id); OEMCryptoCipherMode cipher_mode; OPK_Init_uint32_t((uint32_t*)&cipher_mode); - OPK_Unpack_SelectKey_Request(request, &session, &content_key_id, - &content_key_id_length, &cipher_mode); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); + OPK_Unpack_GetKeyHandle_Request(request, &session, &content_key_id, + &content_key_id_length, &cipher_mode, + &key_handle, &key_handle_length); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); - result = OEMCrypto_SelectKey(session, content_key_id, - content_key_id_length, cipher_mode); - *response = OPK_Pack_SelectKey_Response(result); + LOGD("GetKeyHandle"); + result = + OEMCrypto_GetKeyHandle(session, content_key_id, content_key_id_length, + cipher_mode, key_handle, key_handle_length); + *response = + OPK_Pack_GetKeyHandle_Response(result, key_handle, key_handle_length); break; } - case 105: /* OEMCrypto_DecryptCENC */ + case 134: /* OEMCrypto_DecryptCENC */ { + size_t key_handle_length; + OPK_Init_size_t((size_t*)&key_handle_length); size_t samples_length; OPK_Init_size_t((size_t*)&samples_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); OEMCrypto_SampleDescription* samples; OPK_InitPointer((uint8_t**)&samples); OEMCrypto_CENCEncryptPatternDesc* pattern = @@ -623,12 +639,13 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, sizeof(OEMCrypto_CENCEncryptPatternDesc)); OPK_Init_OEMCrypto_CENCEncryptPatternDesc( (OEMCrypto_CENCEncryptPatternDesc*)pattern); - OPK_Unpack_DecryptCENC_Request(request, &session, &samples, - &samples_length, &pattern); + OPK_Unpack_DecryptCENC_Request(request, &key_handle, &key_handle_length, + &samples, &samples_length, &pattern); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); - result = OEMCrypto_DecryptCENC(session, samples, samples_length, pattern); + result = OEMCrypto_DecryptCENC(key_handle, key_handle_length, samples, + samples_length, pattern); *response = OPK_Pack_DecryptCENC_Response(result); break; } @@ -658,110 +675,122 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_CopyBuffer_Response(result); break; } - case 24: /* OEMCrypto_Generic_Encrypt */ + case 135: /* OEMCrypto_Generic_Encrypt */ { + size_t key_handle_length; + OPK_Init_size_t((size_t*)&key_handle_length); size_t in_buffer_length; OPK_Init_size_t((size_t*)&in_buffer_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); OEMCrypto_SharedMemory* in_buffer; OPK_InitPointer((uint8_t**)&in_buffer); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); OEMCrypto_Algorithm algorithm; OPK_Init_uint32_t((uint32_t*)&algorithm); OEMCrypto_SharedMemory* out_buffer; OPK_InitPointer((uint8_t**)&out_buffer); - OPK_Unpack_Generic_Encrypt_Request(request, &session, &in_buffer, - &in_buffer_length, &iv[0], &algorithm, - &out_buffer); + OPK_Unpack_Generic_Encrypt_Request( + request, &key_handle, &key_handle_length, &in_buffer, + &in_buffer_length, &iv, &algorithm, &out_buffer); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); LOGD("Generic_Encrypt"); - result = OEMCrypto_Generic_Encrypt(session, in_buffer, in_buffer_length, - iv, algorithm, out_buffer); + result = OEMCrypto_Generic_Encrypt(key_handle, key_handle_length, + in_buffer, in_buffer_length, iv, + algorithm, out_buffer); *response = OPK_Pack_Generic_Encrypt_Response( result, in_buffer_length, OPK_SharedBuffer_NextOutputBuffer()); break; } - case 25: /* OEMCrypto_Generic_Decrypt */ + case 136: /* OEMCrypto_Generic_Decrypt */ { + size_t key_handle_length; + OPK_Init_size_t((size_t*)&key_handle_length); size_t in_buffer_length; OPK_Init_size_t((size_t*)&in_buffer_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); OEMCrypto_SharedMemory* in_buffer; OPK_InitPointer((uint8_t**)&in_buffer); - uint8_t iv[16]; - OPK_InitMemory(&iv[0], 16); + uint8_t* iv; + OPK_InitPointer((uint8_t**)&iv); OEMCrypto_Algorithm algorithm; OPK_Init_uint32_t((uint32_t*)&algorithm); OEMCrypto_SharedMemory* out_buffer; OPK_InitPointer((uint8_t**)&out_buffer); - OPK_Unpack_Generic_Decrypt_Request(request, &session, &in_buffer, - &in_buffer_length, &iv[0], &algorithm, - &out_buffer); + OPK_Unpack_Generic_Decrypt_Request( + request, &key_handle, &key_handle_length, &in_buffer, + &in_buffer_length, &iv, &algorithm, &out_buffer); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); LOGD("Generic_Decrypt"); - result = OEMCrypto_Generic_Decrypt(session, in_buffer, in_buffer_length, - iv, algorithm, out_buffer); + result = OEMCrypto_Generic_Decrypt(key_handle, key_handle_length, + in_buffer, in_buffer_length, iv, + algorithm, out_buffer); *response = OPK_Pack_Generic_Decrypt_Response( result, in_buffer_length, OPK_SharedBuffer_NextOutputBuffer()); break; } - case 26: /* OEMCrypto_Generic_Sign */ + case 137: /* OEMCrypto_Generic_Sign */ { + size_t key_handle_length; + OPK_Init_size_t((size_t*)&key_handle_length); size_t buffer_length; OPK_Init_size_t((size_t*)&buffer_length); size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); OPK_Init_size_t(signature_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); OEMCrypto_SharedMemory* buffer; OPK_InitPointer((uint8_t**)&buffer); OEMCrypto_Algorithm algorithm; OPK_Init_uint32_t((uint32_t*)&algorithm); OEMCrypto_SharedMemory* signature; OPK_InitPointer((uint8_t**)&signature); - OPK_Unpack_Generic_Sign_Request(request, &session, &buffer, - &buffer_length, &algorithm, &signature, - &signature_length); + OPK_Unpack_Generic_Sign_Request(request, &key_handle, &key_handle_length, + &buffer, &buffer_length, &algorithm, + &signature, &signature_length); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); LOGD("Generic_Sign"); - result = OEMCrypto_Generic_Sign(session, buffer, buffer_length, algorithm, - signature, signature_length); + result = OEMCrypto_Generic_Sign(key_handle, key_handle_length, buffer, + buffer_length, algorithm, signature, + signature_length); *response = OPK_Pack_Generic_Sign_Response( result, OPK_SharedBuffer_NextOutputBuffer(), signature_length); break; } - case 27: /* OEMCrypto_Generic_Verify */ + case 138: /* OEMCrypto_Generic_Verify */ { + size_t key_handle_length; + OPK_Init_size_t((size_t*)&key_handle_length); size_t buffer_length; OPK_Init_size_t((size_t*)&buffer_length); size_t signature_length; OPK_Init_size_t((size_t*)&signature_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* key_handle; + OPK_InitPointer((uint8_t**)&key_handle); OEMCrypto_SharedMemory* buffer; OPK_InitPointer((uint8_t**)&buffer); OEMCrypto_Algorithm algorithm; OPK_Init_uint32_t((uint32_t*)&algorithm); OEMCrypto_SharedMemory* signature; OPK_InitPointer((uint8_t**)&signature); - OPK_Unpack_Generic_Verify_Request(request, &session, &buffer, - &buffer_length, &algorithm, &signature, - &signature_length); + OPK_Unpack_Generic_Verify_Request( + request, &key_handle, &key_handle_length, &buffer, &buffer_length, + &algorithm, &signature, &signature_length); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; OEMCryptoResult result; OPK_Init_uint32_t((uint32_t*)&result); LOGD("Generic_Verify"); - result = OEMCrypto_Generic_Verify(session, buffer, buffer_length, - algorithm, signature, signature_length); + result = OEMCrypto_Generic_Verify(key_handle, key_handle_length, buffer, + buffer_length, algorithm, signature, + signature_length); *response = OPK_Pack_Generic_Verify_Response(result); break; } @@ -912,22 +941,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, public_cert_length); break; } - case 6: /* OEMCrypto_GetRandom */ - { - size_t random_data_length; - OPK_Init_size_t((size_t*)&random_data_length); - uint8_t* random_data; - OPK_InitPointer((uint8_t**)&random_data); - OPK_Unpack_GetRandom_Request(request, &random_data, &random_data_length); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("GetRandom"); - result = OEMCrypto_GetRandom(random_data, random_data_length); - *response = - OPK_Pack_GetRandom_Response(result, random_data, random_data_length); - break; - } case 22: /* OEMCrypto_APIVersion */ { OPK_Unpack_APIVersion_Request(request); @@ -1143,6 +1156,23 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetWatermarkingSupport_Response(result); break; } + case 139: /* OEMCrypto_GetSignatureHashAlgorithm */ + { + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + OEMCrypto_SignatureHashAlgorithm* algorithm; + OPK_InitPointer((uint8_t**)&algorithm); + OPK_Unpack_GetSignatureHashAlgorithm_Request(request, &session, + &algorithm); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetSignatureHashAlgorithm"); + result = OEMCrypto_GetSignatureHashAlgorithm(session, algorithm); + *response = + OPK_Pack_GetSignatureHashAlgorithm_Response(result, algorithm); + break; + } case 102: /* OEMCrypto_LoadProvisioning */ { size_t message_length; @@ -1520,6 +1550,86 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, wrapped_private_key_length, key_type); break; } + case 131: /* OEMCrypto_GetDeviceInformation */ + { + size_t* device_info_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(device_info_length); + uint8_t* device_info; + OPK_InitPointer((uint8_t**)&device_info); + OPK_Unpack_GetDeviceInformation_Request(request, &device_info, + &device_info_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetDeviceInformation"); + result = OEMCrypto_GetDeviceInformation(device_info, device_info_length); + *response = OPK_Pack_GetDeviceInformation_Response(result, device_info, + device_info_length); + break; + } + case 141: /* OEMCrypto_GetDeviceSignedCsrPayload */ + { + size_t challenge_length; + OPK_Init_size_t((size_t*)&challenge_length); + 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)); + OPK_Init_size_t(signed_csr_payload_length); + uint8_t* challenge; + OPK_InitPointer((uint8_t**)&challenge); + uint8_t* encoded_device_info; + OPK_InitPointer((uint8_t**)&encoded_device_info); + uint8_t* signed_csr_payload; + OPK_InitPointer((uint8_t**)&signed_csr_payload); + OPK_Unpack_GetDeviceSignedCsrPayload_Request( + request, &challenge, &challenge_length, &encoded_device_info, + &encoded_device_info_length, &signed_csr_payload, + &signed_csr_payload_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetDeviceSignedCsrPayload"); + result = OEMCrypto_GetDeviceSignedCsrPayload( + challenge, challenge_length, encoded_device_info, + encoded_device_info_length, signed_csr_payload, + signed_csr_payload_length); + *response = OPK_Pack_GetDeviceSignedCsrPayload_Response( + result, signed_csr_payload, signed_csr_payload_length); + break; + } + case 118: /* OEMCrypto_InstallOemPrivateKey */ + { + size_t wrapped_private_key_length; + OPK_Init_size_t((size_t*)&wrapped_private_key_length); + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + OEMCrypto_PrivateKeyType key_type; + OPK_Init_uint32_t((uint32_t*)&key_type); + uint8_t* wrapped_private_key; + OPK_InitPointer((uint8_t**)&wrapped_private_key); + OPK_Unpack_InstallOemPrivateKey_Request(request, &session, &key_type, + &wrapped_private_key, + &wrapped_private_key_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("InstallOemPrivateKey"); + result = OEMCrypto_InstallOemPrivateKey( + session, key_type, wrapped_private_key, wrapped_private_key_length); + *response = OPK_Pack_InstallOemPrivateKey_Response(result); + break; + } + case 140: /* OEMCrypto_EnterTestMode */ + { + OPK_Unpack_EnterTestMode_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("EnterTestMode"); + result = OEMCrypto_EnterTestMode(); + *response = OPK_Pack_EnterTestMode_Response(result); + break; + } case 86: /* OEMCrypto_SupportsDecryptHash */ { OPK_Unpack_SupportsDecryptHash_Request(request); @@ -1610,74 +1720,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_FreeSecureBuffer_Response(result, output_descriptor); break; } - case 118: /* OEMCrypto_InstallOemPrivateKey */ - { - size_t wrapped_private_key_length; - OPK_Init_size_t((size_t*)&wrapped_private_key_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - OEMCrypto_PrivateKeyType key_type; - OPK_Init_uint32_t((uint32_t*)&key_type); - uint8_t* wrapped_private_key; - OPK_InitPointer((uint8_t**)&wrapped_private_key); - OPK_Unpack_InstallOemPrivateKey_Request(request, &session, &key_type, - &wrapped_private_key, - &wrapped_private_key_length); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("InstallOemPrivateKey"); - result = OEMCrypto_InstallOemPrivateKey( - session, key_type, wrapped_private_key, wrapped_private_key_length); - *response = OPK_Pack_InstallOemPrivateKey_Response(result); - break; - } - case 119: /* OEMCrypto_ReassociateEntitledKeySession */ - { - OEMCrypto_SESSION key_session; - OPK_Init_uint32_t((uint32_t*)&key_session); - OEMCrypto_SESSION oec_session; - OPK_Init_uint32_t((uint32_t*)&oec_session); - OPK_Unpack_ReassociateEntitledKeySession_Request(request, &key_session, - &oec_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("ReassociateEntitledKeySession"); - result = - OEMCrypto_ReassociateEntitledKeySession(key_session, oec_session); - *response = OPK_Pack_ReassociateEntitledKeySession_Response(result); - break; - } - case 120: /* OEMCrypto_LoadCasECMKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - OEMCrypto_EntitledContentKeyObject* even_key = - (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( - sizeof(OEMCrypto_EntitledContentKeyObject)); - OPK_Init_OEMCrypto_EntitledContentKeyObject( - (OEMCrypto_EntitledContentKeyObject*)even_key); - OEMCrypto_EntitledContentKeyObject* odd_key = - (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( - sizeof(OEMCrypto_EntitledContentKeyObject)); - OPK_Init_OEMCrypto_EntitledContentKeyObject( - (OEMCrypto_EntitledContentKeyObject*)odd_key); - OPK_Unpack_LoadCasECMKeys_Request(request, &session, &message, - &message_length, &even_key, &odd_key); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("LoadCasECMKeys"); - result = OEMCrypto_LoadCasECMKeys(session, message, message_length, - even_key, odd_key); - *response = OPK_Pack_LoadCasECMKeys_Response(result); - break; - } case 115: /* OEMCrypto_OPK_SerializationVersion */ { uint32_t* ree_major = (uint32_t*)OPK_VarAlloc(sizeof(uint32_t)); diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c index d12769e..0310c8e 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c @@ -69,6 +69,29 @@ ODK_Message OPK_Pack_Initialize_Response(OEMCryptoResult result) { return msg; } +void OPK_Unpack_SetMaxAPIVersion_Request(ODK_Message* msg, + uint32_t* max_version) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 132) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, max_version); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_SetMaxAPIVersion_Response(OEMCryptoResult result) { + uint32_t api_value = 132; /* from _oecc132 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_Terminate_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -186,56 +209,6 @@ ODK_Message OPK_Pack_CloseSession_Response(OEMCryptoResult result) { return msg; } -void OPK_Unpack_CreateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* oec_session, - OEMCrypto_SESSION** key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 111) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, oec_session); - *key_session = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_CreateEntitledKeySession_Response( - OEMCryptoResult result, const OEMCrypto_SESSION* key_session) { - uint32_t api_value = 111; /* from _oecc111 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackNullable_uint32_t(&msg, key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RemoveEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 112) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, key_session); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result) { - uint32_t api_value = 112; /* from _oecc112 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_GenerateDerivedKeys_Request( ODK_Message* msg, OEMCrypto_SESSION* session, OEMCrypto_SharedMemory** mac_key_context, size_t* mac_key_context_length, @@ -423,75 +396,6 @@ ODK_Message OPK_Pack_PrepAndSignRenewalRequest_Response( return msg; } -void OPK_Unpack_LoadKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, uint8_t** signature, size_t* signature_length, - OEMCrypto_Substring* enc_mac_keys_iv, OEMCrypto_Substring* enc_mac_keys, - size_t* key_array_length, OEMCrypto_KeyObject** key_array, - OEMCrypto_Substring* pst, OEMCrypto_Substring* srm_restriction_data, - OEMCrypto_LicenseType* license_type) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 83) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_size_t(msg, signature_length); - OPK_Unpack_size_t(msg, key_array_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - OPK_UnpackInPlace(msg, (uint8_t**)signature, - OPK_FromSizeTPtr(signature_length)); - OPK_Unpack_OEMCrypto_Substring(msg, enc_mac_keys_iv); - OPK_Unpack_OEMCrypto_Substring(msg, enc_mac_keys); - /* unpack object array with unpacker function OPK_Unpack_OEMCrypto_KeyObject - */ - ODK_Message* odk_message = msg; - void** address = (void**)key_array; - LengthType count = OPK_FromSizeTPtr(key_array_length); - size_t size = sizeof(OEMCrypto_KeyObject); - if (address) { - *address = NULL; - } - if (!OPK_UnpackIsNull(odk_message)) { - if (address && !OPK_LengthIsNull(count)) { - size_t bytes_to_unpack = 0; - if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR); - } else { - *address = OPK_BumpAllocate(bytes_to_unpack); - if (!*address) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); - } else { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Unpack_OEMCrypto_KeyObject( - odk_message, (OEMCrypto_KeyObject*)((*address) + size * i)); - } - } - } - } - } - OPK_Unpack_OEMCrypto_Substring(msg, pst); - OPK_Unpack_OEMCrypto_Substring(msg, srm_restriction_data); - OPK_Unpack_uint32_t(msg, license_type); - if (!Is_Valid_OEMCrypto_LicenseType(*license_type)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_LoadKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 83; /* from _oecc83 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_LoadLicense_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -525,96 +429,6 @@ ODK_Message OPK_Pack_LoadLicense_Response(OEMCryptoResult result) { return msg; } -void OPK_Unpack_LoadEntitledContentKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, size_t* key_array_length, - OEMCrypto_EntitledContentKeyObject** key_array) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 121) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_size_t(msg, key_array_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - /* unpack object array with unpacker function - * OPK_Unpack_OEMCrypto_EntitledContentKeyObject */ - ODK_Message* odk_message = msg; - void** address = (void**)key_array; - LengthType count = OPK_FromSizeTPtr(key_array_length); - size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); - if (address) { - *address = NULL; - } - if (!OPK_UnpackIsNull(odk_message)) { - if (address && !OPK_LengthIsNull(count)) { - size_t bytes_to_unpack = 0; - if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR); - } else { - *address = OPK_BumpAllocate(bytes_to_unpack); - if (!*address) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); - } else { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Unpack_OEMCrypto_EntitledContentKeyObject( - odk_message, - (OEMCrypto_EntitledContentKeyObject*)((*address) + size * i)); - } - } - } - } - } - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 121; /* from _oecc121 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RefreshKeys_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, - uint8_t** message, size_t* message_length, - uint8_t** signature, - size_t* signature_length, size_t* num_keys, - OEMCrypto_KeyRefreshObject** key_array) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 91) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_size_t(msg, signature_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - OPK_UnpackInPlace(msg, (uint8_t**)signature, - OPK_FromSizeTPtr(signature_length)); - OPK_Unpack_size_t(msg, num_keys); - OPK_UnpackNullable_OEMCrypto_KeyRefreshObject(msg, key_array); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_RefreshKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 91; /* from _oecc91 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_LoadRenewal_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -688,30 +502,48 @@ ODK_Message OPK_Pack_QueryKeyControl_Response( return msg; } -void OPK_Unpack_SelectKey_Request(ODK_Message* msg, OEMCrypto_SESSION* session, - uint8_t** content_key_id, - size_t* content_key_id_length, - OEMCryptoCipherMode* cipher_mode) { +void OPK_Unpack_CreateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* oec_session, + OEMCrypto_SESSION** key_session) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 81) + if (api_value != 111) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, content_key_id_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)content_key_id, - OPK_FromSizeTPtr(content_key_id_length)); - OPK_Unpack_uint32_t(msg, cipher_mode); - if (!Is_Valid_OEMCryptoCipherMode(*cipher_mode)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } + OPK_Unpack_uint32_t(msg, oec_session); + *key_session = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); OPK_UnpackEOM(msg); OPK_SharedBuffer_FinalizeUnpacking(); } -ODK_Message OPK_Pack_SelectKey_Response(OEMCryptoResult result) { - uint32_t api_value = 81; /* from _oecc81 */ +ODK_Message OPK_Pack_CreateEntitledKeySession_Response( + OEMCryptoResult result, const OEMCrypto_SESSION* key_session) { + uint32_t api_value = 111; /* from _oecc111 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_uint32_t(&msg, key_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_RemoveEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 112) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, key_session); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result) { + uint32_t api_value = 112; /* from _oecc112 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -720,18 +552,209 @@ ODK_Message OPK_Pack_SelectKey_Response(OEMCryptoResult result) { return msg; } +void OPK_Unpack_LoadEntitledContentKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 121) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, message_length); + OPK_Unpack_size_t(msg, key_array_length); + OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); + /* unpack object array with unpacker function + * OPK_Unpack_OEMCrypto_EntitledContentKeyObject */ + ODK_Message* odk_message = msg; + void** address = (void**)key_array; + LengthType count = OPK_FromSizeTPtr(key_array_length); + size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); + if (address) { + *address = NULL; + } + if (!OPK_UnpackIsNull(odk_message)) { + if (address && !OPK_LengthIsNull(count)) { + size_t bytes_to_unpack = 0; + if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) { + ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR); + } else { + *address = OPK_BumpAllocate(bytes_to_unpack); + if (!*address) { + ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); + } else { + for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + uint8_t* new_address = (uint8_t*)(*address) + size * i; + OPK_Unpack_OEMCrypto_EntitledContentKeyObject( + odk_message, + (OEMCrypto_EntitledContentKeyObject*)((void*)new_address)); + } + } + } + } + } + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result) { + uint32_t api_value = 121; /* from _oecc121 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ReassociateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session, + OEMCrypto_SESSION* oec_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 119) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, key_session); + OPK_Unpack_uint32_t(msg, oec_session); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( + OEMCryptoResult result) { + uint32_t api_value = 119; /* from _oecc119 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadCasECMKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, + OEMCrypto_EntitledContentKeyObject** odd_key) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 120) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, message_length); + OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); + OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, even_key); + OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, odd_key); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result) { + uint32_t api_value = 120; /* from _oecc120 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetOEMKeyToken_Request(ODK_Message* msg, + OEMCrypto_SESSION* key_session, + uint8_t** key_token, + size_t** key_token_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 130) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackNullable_size_t(msg, key_token_length); + OPK_Unpack_uint32_t(msg, key_session); + *key_token = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(key_token_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetOEMKeyToken_Response(OEMCryptoResult result, + const uint8_t* key_token, + const size_t* key_token_length) { + uint32_t api_value = 130; /* from _oecc130 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, key_token_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)key_token, + OPK_FromSizeTPtr(key_token_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetKeyHandle_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** content_key_id, + size_t* content_key_id_length, OEMCryptoCipherMode* cipher_mode, + uint8_t** key_handle, size_t** key_handle_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 133) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, content_key_id_length); + OPK_UnpackNullable_size_t(msg, key_handle_length); + OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)content_key_id, + OPK_FromSizeTPtr(content_key_id_length)); + OPK_Unpack_uint32_t(msg, cipher_mode); + if (!Is_Valid_OEMCryptoCipherMode(*cipher_mode)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + *key_handle = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(key_handle_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetKeyHandle_Response(OEMCryptoResult result, + const uint8_t* key_handle, + const size_t* key_handle_length) { + uint32_t api_value = 133; /* from _oecc133 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, key_handle_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)key_handle, + OPK_FromSizeTPtr(key_handle_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_DecryptCENC_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, + ODK_Message* msg, uint8_t** key_handle, size_t* key_handle_length, OEMCrypto_SampleDescription** samples, size_t* samples_length, OEMCrypto_CENCEncryptPatternDesc** pattern) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 105) + if (api_value != 134) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, key_handle_length); OPK_Unpack_size_t(msg, samples_length); - OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)key_handle, + OPK_FromSizeTPtr(key_handle_length)); /* unpack object array with unpacker function * OPK_Unpack_OEMCrypto_SampleDescription */ ODK_Message* odk_message = msg; @@ -752,9 +775,10 @@ void OPK_Unpack_DecryptCENC_Request( ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); } else { for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + uint8_t* new_address = (uint8_t*)(*address) + size * i; OPK_Unpack_OEMCrypto_SampleDescription( odk_message, - (OEMCrypto_SampleDescription*)((*address) + size * i)); + (OEMCrypto_SampleDescription*)((void*)new_address)); } } } @@ -766,7 +790,7 @@ void OPK_Unpack_DecryptCENC_Request( } ODK_Message OPK_Pack_DecryptCENC_Response(OEMCryptoResult result) { - uint32_t api_value = 105; /* from _oecc105 */ + uint32_t api_value = 134; /* from _oecc134 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -806,23 +830,25 @@ ODK_Message OPK_Pack_CopyBuffer_Response(OEMCryptoResult result) { return msg; } -void OPK_Unpack_Generic_Encrypt_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Encrypt_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** in_buffer, - size_t* in_buffer_length, uint8_t* iv, + size_t* in_buffer_length, uint8_t** iv, OEMCrypto_Algorithm* algorithm, OEMCrypto_SharedMemory** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 24) + if (api_value != 135) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, key_handle_length); OPK_Unpack_size_t(msg, in_buffer_length); - OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)key_handle, + OPK_FromSizeTPtr(key_handle_length)); OPK_UnpackSharedBuffer(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length), /* map */ true, /* is_output */ false); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); OPK_Unpack_uint32_t(msg, algorithm); if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); @@ -836,7 +862,7 @@ void OPK_Unpack_Generic_Encrypt_Request(ODK_Message* msg, ODK_Message OPK_Pack_Generic_Encrypt_Response( OEMCryptoResult result, size_t in_buffer_length, const OEMCrypto_SharedMemory* out_buffer) { - uint32_t api_value = 24; /* from _oecc24 */ + uint32_t api_value = 135; /* from _oecc135 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &in_buffer_length); @@ -851,23 +877,25 @@ ODK_Message OPK_Pack_Generic_Encrypt_Response( return msg; } -void OPK_Unpack_Generic_Decrypt_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Decrypt_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** in_buffer, - size_t* in_buffer_length, uint8_t* iv, + size_t* in_buffer_length, uint8_t** iv, OEMCrypto_Algorithm* algorithm, OEMCrypto_SharedMemory** out_buffer) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 25) + if (api_value != 136) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, key_handle_length); OPK_Unpack_size_t(msg, in_buffer_length); - OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)key_handle, + OPK_FromSizeTPtr(key_handle_length)); OPK_UnpackSharedBuffer(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length), /* map */ true, /* is_output */ false); - OPK_UnpackArray(msg, &iv[0], 16); + OPK_UnpackInPlace(msg, (uint8_t**)iv, OPK_ToLengthType(16)); OPK_Unpack_uint32_t(msg, algorithm); if (!Is_Valid_OEMCrypto_Algorithm(*algorithm)) { ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); @@ -881,7 +909,7 @@ void OPK_Unpack_Generic_Decrypt_Request(ODK_Message* msg, ODK_Message OPK_Pack_Generic_Decrypt_Response( OEMCryptoResult result, size_t in_buffer_length, const OEMCrypto_SharedMemory* out_buffer) { - uint32_t api_value = 25; /* from _oecc25 */ + uint32_t api_value = 136; /* from _oecc136 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &in_buffer_length); @@ -896,8 +924,8 @@ ODK_Message OPK_Pack_Generic_Decrypt_Response( return msg; } -void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** buffer, size_t* buffer_length, OEMCrypto_Algorithm* algorithm, @@ -905,13 +933,15 @@ void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 26) + if (api_value != 137) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, key_handle_length); OPK_Unpack_size_t(msg, buffer_length); OPK_UnpackNullable_size_t(msg, signature_length); - OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)key_handle, + OPK_FromSizeTPtr(key_handle_length)); OPK_UnpackSharedBuffer(msg, buffer, OPK_FromSizeTPtr(buffer_length), /* map */ true, /* is_output */ false); OPK_Unpack_uint32_t(msg, algorithm); @@ -927,7 +957,7 @@ void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, ODK_Message OPK_Pack_Generic_Sign_Response( OEMCryptoResult result, const OEMCrypto_SharedMemory* signature, const size_t* signature_length) { - uint32_t api_value = 26; /* from _oecc26 */ + uint32_t api_value = 137; /* from _oecc137 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -942,8 +972,8 @@ ODK_Message OPK_Pack_Generic_Sign_Response( return msg; } -void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** buffer, size_t* buffer_length, OEMCrypto_Algorithm* algorithm, @@ -951,13 +981,15 @@ void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, size_t* signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 27) + if (api_value != 138) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, key_handle_length); OPK_Unpack_size_t(msg, buffer_length); OPK_Unpack_size_t(msg, signature_length); - OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)key_handle, + OPK_FromSizeTPtr(key_handle_length)); OPK_UnpackSharedBuffer(msg, buffer, OPK_FromSizeTPtr(buffer_length), /* map */ true, /* is_output */ false); OPK_Unpack_uint32_t(msg, algorithm); @@ -971,7 +1003,7 @@ void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, } ODK_Message OPK_Pack_Generic_Verify_Response(OEMCryptoResult result) { - uint32_t api_value = 27; /* from _oecc27 */ + uint32_t api_value = 138; /* from _oecc138 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1233,38 +1265,6 @@ ODK_Message OPK_Pack_GetOEMPublicCertificate_Response( return msg; } -void OPK_Unpack_GetRandom_Request(ODK_Message* msg, uint8_t** random_data, - size_t* random_data_length) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 6) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, random_data_length); - *random_data = (uint8_t*)OPK_UnpackAllocBuffer( - msg, OPK_FromSizeTPtr(random_data_length), sizeof(uint8_t)); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_GetRandom_Response(OEMCryptoResult result, - const uint8_t* random_data, - size_t random_data_length) { - uint32_t api_value = 6; /* from _oecc6 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_size_t(&msg, &random_data_length); - OPK_Pack_uint32_t(&msg, &result); - if (SuccessResult(result)) { - OPK_PackMemory(&msg, (const uint8_t*)random_data, - OPK_ToLengthType(random_data_length)); - } - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_APIVersion_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -1679,6 +1679,34 @@ ODK_Message OPK_Pack_GetWatermarkingSupport_Response( return msg; } +void OPK_Unpack_GetSignatureHashAlgorithm_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_SignatureHashAlgorithm** algorithm) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 139) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, session); + *algorithm = + (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_SignatureHashAlgorithm)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Response( + OEMCryptoResult result, const OEMCrypto_SignatureHashAlgorithm* algorithm) { + uint32_t api_value = 139; /* from _oecc139 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_uint32_t(&msg, algorithm); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_LoadProvisioning_Request( ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, size_t* core_message_length, uint8_t** signature, @@ -2269,6 +2297,132 @@ ODK_Message OPK_Pack_GenerateCertificateKeyPair_Response( return msg; } +void OPK_Unpack_GetDeviceInformation_Request(ODK_Message* msg, + uint8_t** device_info, + size_t** device_info_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 131) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackNullable_size_t(msg, device_info_length); + *device_info = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(device_info_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetDeviceInformation_Response( + OEMCryptoResult result, const uint8_t* device_info, + const size_t* device_info_length) { + uint32_t api_value = 131; /* from _oecc131 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, device_info_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)device_info, + OPK_FromSizeTPtr(device_info_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetDeviceSignedCsrPayload_Request( + ODK_Message* msg, uint8_t** challenge, size_t* challenge_length, + uint8_t** encoded_device_info, size_t* encoded_device_info_length, + uint8_t** signed_csr_payload, size_t** signed_csr_payload_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 141) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, challenge_length); + OPK_Unpack_size_t(msg, encoded_device_info_length); + OPK_UnpackNullable_size_t(msg, signed_csr_payload_length); + OPK_UnpackInPlace(msg, (uint8_t**)challenge, + OPK_FromSizeTPtr(challenge_length)); + OPK_UnpackInPlace(msg, (uint8_t**)encoded_device_info, + OPK_FromSizeTPtr(encoded_device_info_length)); + *signed_csr_payload = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(signed_csr_payload_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetDeviceSignedCsrPayload_Response( + OEMCryptoResult result, const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length) { + uint32_t api_value = 141; /* from _oecc141 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, signed_csr_payload_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)signed_csr_payload, + OPK_FromSizeTPtr(signed_csr_payload_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_InstallOemPrivateKey_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, + size_t* wrapped_private_key_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 118) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, wrapped_private_key_length); + OPK_Unpack_uint32_t(msg, session); + OPK_Unpack_uint32_t(msg, key_type); + if (!Is_Valid_OEMCrypto_PrivateKeyType(*key_type)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackInPlace(msg, (uint8_t**)wrapped_private_key, + OPK_FromSizeTPtr(wrapped_private_key_length)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result) { + uint32_t api_value = 118; /* from _oecc118 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_EnterTestMode_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 140) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_EnterTestMode_Response(OEMCryptoResult result) { + uint32_t api_value = 140; /* from _oecc140 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_SupportsDecryptHash_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -2406,93 +2560,6 @@ ODK_Message OPK_Pack_FreeSecureBuffer_Response( return msg; } -void OPK_Unpack_InstallOemPrivateKey_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, - OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, - size_t* wrapped_private_key_length) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 118) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, wrapped_private_key_length); - OPK_Unpack_uint32_t(msg, session); - OPK_Unpack_uint32_t(msg, key_type); - if (!Is_Valid_OEMCrypto_PrivateKeyType(*key_type)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackInPlace(msg, (uint8_t**)wrapped_private_key, - OPK_FromSizeTPtr(wrapped_private_key_length)); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result) { - uint32_t api_value = 118; /* from _oecc118 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_ReassociateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session, - OEMCrypto_SESSION* oec_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 119) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, key_session); - OPK_Unpack_uint32_t(msg, oec_session); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( - OEMCryptoResult result) { - uint32_t api_value = 119; /* from _oecc119 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadCasECMKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, - OEMCrypto_EntitledContentKeyObject** odd_key) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 120) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, even_key); - OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, odd_key); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 120; /* from _oecc120 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_OPK_SerializationVersion_Request(ODK_Message* msg, uint32_t** ree_major, uint32_t** ree_minor, diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h index 3bc2ccc..97316e2 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h @@ -22,6 +22,9 @@ void OPK_Unpack_SetSandbox_Request(ODK_Message* msg, uint8_t** sandbox_id, ODK_Message OPK_Pack_SetSandbox_Response(OEMCryptoResult result); void OPK_Unpack_Initialize_Request(ODK_Message* msg); ODK_Message OPK_Pack_Initialize_Response(OEMCryptoResult result); +void OPK_Unpack_SetMaxAPIVersion_Request(ODK_Message* msg, + uint32_t* max_version); +ODK_Message OPK_Pack_SetMaxAPIVersion_Response(OEMCryptoResult result); void OPK_Unpack_Terminate_Request(ODK_Message* msg); ODK_Message OPK_Pack_Terminate_Response(OEMCryptoResult result); void OPK_Unpack_Idle_Request(ODK_Message* msg, OEMCrypto_IdleState* state, @@ -36,14 +39,6 @@ ODK_Message OPK_Pack_OpenSession_Response(OEMCryptoResult result, void OPK_Unpack_CloseSession_Request(ODK_Message* msg, OEMCrypto_SESSION* session); ODK_Message OPK_Pack_CloseSession_Response(OEMCryptoResult result); -void OPK_Unpack_CreateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* oec_session, - OEMCrypto_SESSION** key_session); -ODK_Message OPK_Pack_CreateEntitledKeySession_Response( - OEMCryptoResult result, const OEMCrypto_SESSION* key_session); -void OPK_Unpack_RemoveEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session); -ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result); void OPK_Unpack_GenerateDerivedKeys_Request( ODK_Message* msg, OEMCrypto_SESSION* session, OEMCrypto_SharedMemory** mac_key_context, size_t* mac_key_context_length, @@ -76,14 +71,6 @@ ODK_Message OPK_Pack_PrepAndSignRenewalRequest_Response( OEMCryptoResult result, const uint8_t* message, size_t message_length, const size_t* core_message_size, const uint8_t* signature, const size_t* signature_length); -void OPK_Unpack_LoadKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, uint8_t** signature, size_t* signature_length, - OEMCrypto_Substring* enc_mac_keys_iv, OEMCrypto_Substring* enc_mac_keys, - size_t* key_array_length, OEMCrypto_KeyObject** key_array, - OEMCrypto_Substring* pst, OEMCrypto_Substring* srm_restriction_data, - OEMCrypto_LicenseType* license_type); -ODK_Message OPK_Pack_LoadKeys_Response(OEMCryptoResult result); void OPK_Unpack_LoadLicense_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -91,18 +78,6 @@ void OPK_Unpack_LoadLicense_Request(ODK_Message* msg, uint8_t** signature, size_t* signature_length); ODK_Message OPK_Pack_LoadLicense_Response(OEMCryptoResult result); -void OPK_Unpack_LoadEntitledContentKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, size_t* key_array_length, - OEMCrypto_EntitledContentKeyObject** key_array); -ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result); -void OPK_Unpack_RefreshKeys_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, - uint8_t** message, size_t* message_length, - uint8_t** signature, - size_t* signature_length, size_t* num_keys, - OEMCrypto_KeyRefreshObject** key_array); -ODK_Message OPK_Pack_RefreshKeys_Response(OEMCryptoResult result); void OPK_Unpack_LoadRenewal_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -119,13 +94,45 @@ void OPK_Unpack_QueryKeyControl_Request(ODK_Message* msg, ODK_Message OPK_Pack_QueryKeyControl_Response( OEMCryptoResult result, const uint8_t* key_control_block, const size_t* key_control_block_length); -void OPK_Unpack_SelectKey_Request(ODK_Message* msg, OEMCrypto_SESSION* session, - uint8_t** content_key_id, - size_t* content_key_id_length, - OEMCryptoCipherMode* cipher_mode); -ODK_Message OPK_Pack_SelectKey_Response(OEMCryptoResult result); -void OPK_Unpack_DecryptCENC_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_CreateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* oec_session, + OEMCrypto_SESSION** key_session); +ODK_Message OPK_Pack_CreateEntitledKeySession_Response( + OEMCryptoResult result, const OEMCrypto_SESSION* key_session); +void OPK_Unpack_RemoveEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session); +ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result); +void OPK_Unpack_LoadEntitledContentKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array); +ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result); +void OPK_Unpack_ReassociateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session, + OEMCrypto_SESSION* oec_session); +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( + OEMCryptoResult result); +void OPK_Unpack_LoadCasECMKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, + OEMCrypto_EntitledContentKeyObject** odd_key); +ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result); +void OPK_Unpack_GetOEMKeyToken_Request(ODK_Message* msg, + OEMCrypto_SESSION* key_session, + uint8_t** key_token, + size_t** key_token_length); +ODK_Message OPK_Pack_GetOEMKeyToken_Response(OEMCryptoResult result, + const uint8_t* key_token, + const size_t* key_token_length); +void OPK_Unpack_GetKeyHandle_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** content_key_id, + size_t* content_key_id_length, OEMCryptoCipherMode* cipher_mode, + uint8_t** key_handle, size_t** key_handle_length); +ODK_Message OPK_Pack_GetKeyHandle_Response(OEMCryptoResult result, + const uint8_t* key_handle, + const size_t* key_handle_length); +void OPK_Unpack_DecryptCENC_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SampleDescription** samples, size_t* samples_length, OEMCrypto_CENCEncryptPatternDesc** pattern); @@ -135,26 +142,26 @@ void OPK_Unpack_CopyBuffer_Request( OEMCrypto_SharedMemory** data_addr, size_t* data_addr_length, OEMCrypto_DestBufferDesc** out_buffer_descriptor, uint8_t* subsample_flags); ODK_Message OPK_Pack_CopyBuffer_Response(OEMCryptoResult result); -void OPK_Unpack_Generic_Encrypt_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Encrypt_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** in_buffer, - size_t* in_buffer_length, uint8_t* iv, + size_t* in_buffer_length, uint8_t** iv, OEMCrypto_Algorithm* algorithm, OEMCrypto_SharedMemory** out_buffer); ODK_Message OPK_Pack_Generic_Encrypt_Response( OEMCryptoResult result, size_t in_buffer_length, const OEMCrypto_SharedMemory* out_buffer); -void OPK_Unpack_Generic_Decrypt_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Decrypt_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** in_buffer, - size_t* in_buffer_length, uint8_t* iv, + size_t* in_buffer_length, uint8_t** iv, OEMCrypto_Algorithm* algorithm, OEMCrypto_SharedMemory** out_buffer); ODK_Message OPK_Pack_Generic_Decrypt_Response( OEMCryptoResult result, size_t in_buffer_length, const OEMCrypto_SharedMemory* out_buffer); -void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** buffer, size_t* buffer_length, OEMCrypto_Algorithm* algorithm, @@ -163,8 +170,8 @@ void OPK_Unpack_Generic_Sign_Request(ODK_Message* msg, ODK_Message OPK_Pack_Generic_Sign_Response( OEMCryptoResult result, const OEMCrypto_SharedMemory* signature, const size_t* signature_length); -void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, - OEMCrypto_SESSION* session, +void OPK_Unpack_Generic_Verify_Request(ODK_Message* msg, uint8_t** key_handle, + size_t* key_handle_length, OEMCrypto_SharedMemory** buffer, size_t* buffer_length, OEMCrypto_Algorithm* algorithm, @@ -209,11 +216,6 @@ void OPK_Unpack_GetOEMPublicCertificate_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetOEMPublicCertificate_Response( OEMCryptoResult result, const uint8_t* public_cert, const size_t* public_cert_length); -void OPK_Unpack_GetRandom_Request(ODK_Message* msg, uint8_t** random_data, - size_t* random_data_length); -ODK_Message OPK_Pack_GetRandom_Response(OEMCryptoResult result, - const uint8_t* random_data, - size_t random_data_length); void OPK_Unpack_APIVersion_Request(ODK_Message* msg); ODK_Message OPK_Pack_APIVersion_Response(uint32_t result); void OPK_Unpack_MinorAPIVersion_Request(ODK_Message* msg); @@ -265,6 +267,11 @@ ODK_Message OPK_Pack_ProductionReady_Response(OEMCryptoResult result); void OPK_Unpack_GetWatermarkingSupport_Request(ODK_Message* msg); ODK_Message OPK_Pack_GetWatermarkingSupport_Response( OEMCrypto_WatermarkingSupport result); +void OPK_Unpack_GetSignatureHashAlgorithm_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_SignatureHashAlgorithm** algorithm); +ODK_Message OPK_Pack_GetSignatureHashAlgorithm_Response( + OEMCryptoResult result, const OEMCrypto_SignatureHashAlgorithm* algorithm); void OPK_Unpack_LoadProvisioning_Request( ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, size_t* core_message_length, uint8_t** signature, @@ -370,6 +377,26 @@ ODK_Message OPK_Pack_GenerateCertificateKeyPair_Response( const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const OEMCrypto_PrivateKeyType* key_type); +void OPK_Unpack_GetDeviceInformation_Request(ODK_Message* msg, + uint8_t** device_info, + size_t** device_info_length); +ODK_Message OPK_Pack_GetDeviceInformation_Response( + OEMCryptoResult result, const uint8_t* device_info, + const size_t* device_info_length); +void OPK_Unpack_GetDeviceSignedCsrPayload_Request( + ODK_Message* msg, uint8_t** challenge, size_t* challenge_length, + uint8_t** encoded_device_info, size_t* encoded_device_info_length, + uint8_t** signed_csr_payload, size_t** signed_csr_payload_length); +ODK_Message OPK_Pack_GetDeviceSignedCsrPayload_Response( + OEMCryptoResult result, const uint8_t* signed_csr_payload, + const size_t* signed_csr_payload_length); +void OPK_Unpack_InstallOemPrivateKey_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, + size_t* wrapped_private_key_length); +ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result); +void OPK_Unpack_EnterTestMode_Request(ODK_Message* msg); +ODK_Message OPK_Pack_EnterTestMode_Response(OEMCryptoResult result); void OPK_Unpack_SupportsDecryptHash_Request(ODK_Message* msg); ODK_Message OPK_Pack_SupportsDecryptHash_Response(uint32_t result); void OPK_Unpack_SetDecryptHash_Request(ODK_Message* msg, @@ -393,21 +420,6 @@ void OPK_Unpack_FreeSecureBuffer_Request( OEMCrypto_DestBufferDesc** output_descriptor, int* secure_fd); ODK_Message OPK_Pack_FreeSecureBuffer_Response( OEMCryptoResult result, const OEMCrypto_DestBufferDesc* output_descriptor); -void OPK_Unpack_InstallOemPrivateKey_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, - OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, - size_t* wrapped_private_key_length); -ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result); -void OPK_Unpack_ReassociateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session, - OEMCrypto_SESSION* oec_session); -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( - OEMCryptoResult result); -void OPK_Unpack_LoadCasECMKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, - OEMCrypto_EntitledContentKeyObject** odd_key); -ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result); void OPK_Unpack_OPK_SerializationVersion_Request(ODK_Message* msg, uint32_t** ree_major, uint32_t** ree_minor, diff --git a/oemcrypto/opk/serialization/tee/tee_version.c b/oemcrypto/opk/serialization/tee/tee_version.c index 43767f4..d5c3490 100644 --- a/oemcrypto/opk/serialization/tee/tee_version.c +++ b/oemcrypto/opk/serialization/tee/tee_version.c @@ -7,6 +7,7 @@ #include "OEMCryptoCENC.h" #include "log_macros.h" +#include "oemcrypto_api_macros.h" #include "version.h" /* @@ -19,6 +20,11 @@ OEMCryptoResult OEMCrypto_OPK_SerializationVersion(uint32_t* ree_major, uint32_t* ree_minor, uint32_t* tee_major, uint32_t* tee_minor) { + // unused variable warning if not debug, since LOG* functions become empty + // expressions + (void)ree_minor; + (void)tee_minor; + if (tee_major) *tee_major = OPK_SERIALIZATION_VERSION_MAJOR; if (tee_minor) *tee_minor = OPK_SERIALIZATION_VERSION_MINOR; diff --git a/oemcrypto/opk/setup.sh b/oemcrypto/opk/setup.sh new file mode 100755 index 0000000..0f23ad1 --- /dev/null +++ b/oemcrypto/opk/setup.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# This script downloads required dependencies to /third_party + +if [ -z "$CDM_DIR" ]; then + export CDM_DIR="$(readlink -e $(dirname $0)/../..)" +fi + +download() { + REPO_URL=$1 + FOLDER_NAME=$2 + CHECKOUT_VAL=$3 + + if [ -d "$FOLDER_NAME" ]; then + echo "$FOLDER_NAME already exists, skipping" + return 0 + fi + + git clone $REPO_URL $FOLDER_NAME + pushd $FOLDER_NAME + git checkout $CHECKOUT_VAL + popd +} + +download_boringssl() { + pushd $CDM_DIR/third_party + mkdir -p boringssl && cd boringssl + mkdir -p kit && cd kit + + # Commits after this change some filenames, which is incompatible with + # current OPK makefiles + download https://boringssl.googlesource.com/boringssl src 1e15682f1a4bb64c48b84884976a2b5c4201e878 + + # generate boringssl source file list + echo "Generating boringssl source file list" + python3 ./src/util/generate_build_files.py android + popd +} + +download_googletest() { + pushd $CDM_DIR/third_party + if [ -d "googletest" ]; then return + fi + git clone --depth 1 https://github.com/google/googletest.git googletest + popd +} + +download_jsmn() { + pushd $CDM_DIR/third_party + download https://github.com/zserge/jsmn.git jsmn v1.0.0 + popd +} + +download_cosec() { + pushd $CDM_DIR/third_party + download https://pigweed.googlesource.com/third_party/github/cose-wg/COSE-C COSE-C 97d1805e71b7a6770093c5e6790d46611680d563 + popd +} + +download_cncbor() { + pushd $CDM_DIR/third_party + download https://pigweed.googlesource.com/third_party/github/jimsch/cn-cbor cn-cbor f713bf67bcf3e076d47e474ce060252ef8be48c7 + popd +} + +download_opendice() { + pushd $CDM_DIR/third_party + download https://pigweed.googlesource.com/open-dice/ open-dice 55a2cda + popd +} + +setup_third_party() { + pushd $CDM_DIR + mkdir -p third_party + + download_googletest + download_boringssl + download_jsmn + download_cosec + download_cncbor + download_opendice + popd +} + +setup_third_party + diff --git a/oemcrypto/test/Android.mk b/oemcrypto/test/Android.mk index 5d86cda..98e9b4d 100644 --- a/oemcrypto/test/Android.mk +++ b/oemcrypto/test/Android.mk @@ -6,13 +6,15 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/cdm/util/include \ LOCAL_MODULE:=oemcrypto_test -LOCAL_LICENSE_KINDS:=legacy_by_exception_only -LOCAL_LICENSE_CONDITIONS:=by_exception_only +LOCAL_LICENSE_KINDS:=legacy_by_exception_only legacy_proprietary +LOCAL_LICENSE_CONDITIONS:=by_exception_only proprietary by_exception_only LOCAL_MODULE_TAGS := tests LOCAL_MODULE_OWNER := widevine LOCAL_PROPRIETARY_MODULE := true +LOCAL_C_INCLUDES += external/googletest/googlemock/include \ + # When built, explicitly put it in the DATA/nativetest directory. LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest diff --git a/oemcrypto/test/GEN_api_lock_file.c b/oemcrypto/test/GEN_api_lock_file.c new file mode 100644 index 0000000..2a29201 --- /dev/null +++ b/oemcrypto/test/GEN_api_lock_file.c @@ -0,0 +1,368 @@ +// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// This code is semi-auto-generated, do not edit unless you know what you are +// doing. The script oemcrypto/lock-api-for-release will append to this file. +// +// If this file does not build, then you have modified an OEMCrypto API +// function. Instead, you should rename the old function and give the modified +// function a new oecc number. + +#include "OEMCryptoCENC.h" + +// This initial generation of this file was for v16.4, so older functions will +// not have an accurate version number. + +OEMCryptoResult _oecc84(const uint8_t* sandbox_id, size_t sandbox_id_length); +OEMCryptoResult _oecc01(void); +OEMCryptoResult _oecc02(void); +OEMCryptoResult _oecc09(OEMCrypto_SESSION* session); +OEMCryptoResult _oecc10(OEMCrypto_SESSION session); +OEMCryptoResult _oecc95(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* mac_key_context, + size_t mac_key_context_length, + const OEMCrypto_SharedMemory* enc_key_context, + size_t enc_key_context_length); +OEMCryptoResult _oecc21(OEMCrypto_SESSION session, + const uint8_t* derivation_key, + size_t derivation_key_length, + const OEMCrypto_SharedMemory* mac_key_context, + size_t mac_key_context_length, + const OEMCrypto_SharedMemory* enc_key_context, + size_t enc_key_context_length); +OEMCryptoResult _oecc14(OEMCrypto_SESSION session, uint32_t* nonce); +OEMCryptoResult _oecc96(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc97(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc98(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc55(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc83( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t key_array_length, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type); +OEMCryptoResult _oecc99(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length); +OEMCryptoResult _oecc92( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject_V16* key_array); +OEMCryptoResult _oecc91(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length, size_t num_keys, + const OEMCrypto_KeyRefreshObject* key_array); +OEMCryptoResult _oecc101(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length); +OEMCryptoResult _oecc41(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length); +OEMCryptoResult _oecc81(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode); +OEMCryptoResult _oecc105( + OEMCrypto_SESSION session, + const OEMCrypto_SampleDescription* samples, // an array of samples. + size_t samples_length, // the number of samples. + const OEMCrypto_CENCEncryptPatternDesc* pattern); +OEMCryptoResult _oecc93(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* data_addr, + size_t data_addr_length, + const OEMCrypto_DestBufferDesc* out_buffer_descriptor, + uint8_t subsample_flags); +OEMCryptoResult _oecc24(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult _oecc25(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult _oecc26(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* signature, + size_t* signature_length); +OEMCryptoResult _oecc27(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + const OEMCrypto_SharedMemory* signature, + size_t signature_length); +OEMCryptoResult _oecc08(const uint8_t* keybox_or_cert, + size_t keybox_or_cert_length, + uint8_t* wrapped_keybox_or_cert, + size_t* wrapped_keybox_or_cert_length, + const uint8_t* transport_key, + size_t transport_key_length); +OEMCryptoResult _oecc03(const uint8_t* keybox_or_cert, + size_t keybox_or_cert_length); +OEMCrypto_ProvisioningMethod _oecc49(void); +OEMCryptoResult _oecc05(void); +OEMCryptoResult _oecc07(uint8_t* device_id, size_t* device_id_length); +OEMCryptoResult _oecc04(uint8_t* key_data, size_t* key_data_length); +OEMCryptoResult _oecc78(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc103(OEMCrypto_SESSION session); +OEMCryptoResult _oecc104(uint8_t* public_cert, size_t* public_cert_length); +OEMCryptoResult _oecc06(uint8_t* random_data, size_t random_data_length); +uint32_t _oecc22(void); +uint32_t _oecc108(void); +uint8_t _oecc46(void); +OEMCryptoResult _oecc44(OEMCrypto_HDCP_Capability* current, + OEMCrypto_HDCP_Capability* maximum); +bool _oecc29(void); +size_t _oecc94(void); +bool _oecc39(void); +OEMCryptoResult _oecc38(size_t* count); +OEMCryptoResult _oecc37(size_t* max); +uint32_t _oecc52(void); +bool _oecc53(void); +OEMCryptoResult _oecc54(uint16_t* version); +uint32_t _oecc71(void); +uint32_t _oecc85(void); +OEMCryptoResult _oecc102(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length, + uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length); +OEMCryptoResult _oecc107(OEMCrypto_SESSION session, + OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, + size_t wrapped_private_key_length); +OEMCryptoResult _oecc45(void); +OEMCryptoResult _oecc36(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length, + RSA_Padding_Scheme padding_scheme); +OEMCryptoResult _oecc61(uint8_t* header_buffer, size_t* header_buffer_length); +OEMCryptoResult _oecc62(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc63(OEMCrypto_SESSION session, + uint32_t* usage_entry_number); +OEMCryptoResult _oecc64(OEMCrypto_SESSION session, uint32_t usage_entry_number, + const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc65(OEMCrypto_SESSION session, + OEMCrypto_SharedMemory* header_buffer, + size_t* header_buffer_length, + OEMCrypto_SharedMemory* entry_buffer, + size_t* entry_buffer_length); +OEMCryptoResult _oecc66(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length); +OEMCryptoResult _oecc32(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length, uint8_t* buffer, + size_t* buffer_length); +OEMCryptoResult _oecc68(OEMCrypto_SESSION session, uint32_t new_index); +OEMCryptoResult _oecc67(uint32_t new_entry_count, uint8_t* header_buffer, + size_t* header_buffer_length); +OEMCryptoResult _oecc57(void); +uint32_t _oecc86(void); +OEMCryptoResult _oecc88(OEMCrypto_SESSION session, uint32_t frame_number, + const uint8_t* hash, size_t hash_length); +OEMCryptoResult _oecc89(OEMCrypto_SESSION session, + uint32_t* failed_frame_number); +OEMCryptoResult _oecc109(OEMCrypto_SESSION session, size_t buffer_size, + OEMCrypto_DestBufferDesc* output_descriptor, + int* secure_fd); +OEMCryptoResult _oecc110(OEMCrypto_SESSION session, + OEMCrypto_DestBufferDesc* output_descriptor, + int secure_fd); +OEMCryptoResult _oecc115(uint32_t* ree_major, uint32_t* ree_minor, + uint32_t* tee_major, uint32_t* tee_minor); +OEMCryptoResult _oecc113(OEMCrypto_SESSION session, uint8_t* buffer, + size_t* buffer_length, uint32_t use_test_key); +OEMCryptoResult _oecc114(OEMCrypto_SESSION session, const uint8_t* buffer, + size_t buffer_length, uint32_t use_test_key); +OEMCryptoResult _oecc13(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length); +OEMCryptoResult _oecc51(OEMCrypto_SESSION session, + const uint32_t* unaligned_nonce, + const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length); +OEMCryptoResult _oecc18(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length, + const uint32_t* unaligned_nonce, + const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length); +OEMCryptoResult _oecc30(void); +OEMCryptoResult _oecc33(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length); +OEMCryptoResult _oecc43(const uint8_t* pst, size_t pst_length); +OEMCryptoResult _oecc69(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length); +OEMCryptoResult _oecc34(void); +OEMCryptoResult _oecc70(uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, + uint8_t* server_mac_key, uint8_t* client_mac_key, + const uint8_t* pst, size_t pst_length); +OEMCryptoResult _oecc12(OEMCrypto_SESSION session, + const uint8_t* mac_key_context, + uint32_t mac_key_context_length, + const uint8_t* enc_key_context, + uint32_t enc_key_context_length); +OEMCryptoResult _oecc48(OEMCrypto_SESSION session, const uint8_t* data_addr, + size_t data_addr_length, bool is_encrypted, + const uint8_t* iv, + size_t block_offset, // used for CTR "cenc" mode only. + OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc_V15* pattern, + uint8_t subsample_flags); +OEMCryptoResult _oecc50(OEMCrypto_SESSION session, uint8_t* public_cert, + size_t* public_cert_length); +OEMCryptoResult _oecc19(OEMCrypto_SESSION session, + const uint8_t* wrapped_rsa_key, + size_t wrapped_rsa_key_length); + +// OEMCrypto_Idle defined in v17.1 +OEMCryptoResult _oecc123(OEMCrypto_IdleState state, uint32_t os_specific_code); + +// OEMCrypto_Wake defined in v17.1 +OEMCryptoResult _oecc124(void); + +// OEMCrypto_CreateEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc111(OEMCrypto_SESSION oec_session, + OEMCrypto_SESSION* key_session); + +// OEMCrypto_RemoveEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc112(OEMCrypto_SESSION key_session); + +// OEMCrypto_LoadEntitledContentKeys defined in v17.1 +OEMCryptoResult _oecc121(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); + +// OEMCrypto_BuildInformation defined in v17.1 +OEMCryptoResult _oecc125(char* buffer, size_t* buffer_length); + +// OEMCrypto_SecurityLevel defined in v17.1 +OEMCrypto_Security_Level _oecc126(void); + +// OEMCrypto_GetDTCP2Capability defined in v17.1 +OEMCryptoResult _oecc128(OEMCrypto_DTCP2_Capability* capability); + +// OEMCrypto_ProductionReady defined in v17.1 +OEMCryptoResult _oecc122(void); + +// OEMCrypto_GetWatermarkingSupport defined in v17.1 +OEMCrypto_WatermarkingSupport _oecc129(void); + +// OEMCrypto_ReuseUsageEntry defined in v17.1 +OEMCryptoResult _oecc127(OEMCrypto_SESSION session, + uint32_t usage_entry_number); + +// OEMCrypto_GetBootCertificateChain defined in v17.1 +OEMCryptoResult _oecc116(uint8_t* bcc, size_t* bcc_length, + uint8_t* additional_signature, + size_t* additional_signature_length); + +// OEMCrypto_GenerateCertificateKeyPair defined in v17.1 +OEMCryptoResult _oecc117(OEMCrypto_SESSION session, uint8_t* public_key, + size_t* public_key_length, + uint8_t* public_key_signature, + size_t* public_key_signature_length, + uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length, + OEMCrypto_PrivateKeyType* key_type); + +// OEMCrypto_InstallOemPrivateKey defined in v17.1 +OEMCryptoResult _oecc118(OEMCrypto_SESSION session, + OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, + size_t wrapped_private_key_length); + +// OEMCrypto_ReassociateEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc119(OEMCrypto_SESSION key_session, + OEMCrypto_SESSION oec_session); + +// OEMCrypto_LoadCasECMKeys defined in v17.1 +OEMCryptoResult _oecc120(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); + +// OEMCrypto_GetOEMKeyToken defined in v17.2 +OEMCryptoResult _oecc130(OEMCrypto_SESSION key_session, uint8_t* key_token, + size_t* key_token_length); + +// OEMCrypto_SetMaxAPIVersion defined in v18.1 +OEMCryptoResult _oecc132(uint32_t max_version); + +// OEMCrypto_GetKeyHandle defined in v18.1 +OEMCryptoResult _oecc133(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode, uint8_t* key_handle, + size_t* key_handle_length); + +// OEMCrypto_DecryptCENC defined in v18.1 +OEMCryptoResult _oecc134( + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, // an array of samples. + size_t samples_length, // the number of samples. + const OEMCrypto_CENCEncryptPatternDesc* pattern); + +// OEMCrypto_Generic_Encrypt defined in v18.1 +OEMCryptoResult _oecc135(const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); + +// OEMCrypto_Generic_Decrypt defined in v18.1 +OEMCryptoResult _oecc136(const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); + +// OEMCrypto_Generic_Sign defined in v18.1 +OEMCryptoResult _oecc137(const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* signature, + size_t* signature_length); + +// OEMCrypto_Generic_Verify defined in v18.1 +OEMCryptoResult _oecc138(const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + const OEMCrypto_SharedMemory* signature, + size_t signature_length); + +// OEMCrypto_GetSignatureHashAlgorithm defined in v18.1 +OEMCryptoResult _oecc139(OEMCrypto_SESSION session, + OEMCrypto_SignatureHashAlgorithm* algorithm); + +// OEMCrypto_GetDeviceInformation defined in v18.1 +OEMCryptoResult _oecc131(uint8_t* device_info, size_t* device_info_length); + +// OEMCrypto_GetDeviceSignedCsrPayload defined in v18.1 +OEMCryptoResult _oecc141(const uint8_t* challenge, size_t challenge_length, + const uint8_t* encoded_device_info, + size_t encoded_device_info_length, + uint8_t* signed_csr_payload, + size_t* signed_csr_payload_length); + +// OEMCrypto_EnterTestMode defined in v18.1 +OEMCryptoResult _oecc140(void); diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk index bf5a1a2..ce7a3c8 100644 --- a/oemcrypto/test/common.mk +++ b/oemcrypto/test/common.mk @@ -1,14 +1,5 @@ LOCAL_PATH:= $(call my-dir) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) -HIDL_EXTENSION := _hidl -LIB_BINDER := libhidlbase -else -HIDL_EXTENSION := -LIB_BINDER := libbinder_ndk -endif - ifeq ($(filter mips mips64, $(TARGET_ARCH)),) # Tests need to be compatible with devices that do not support gnu hash-style LOCAL_LDFLAGS+=-Wl,--hash-style=both @@ -18,12 +9,18 @@ endif LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15 LOCAL_SRC_FILES:= \ + GEN_api_lock_file.c \ oec_device_features.cpp \ oec_decrypt_fallback_chain.cpp \ oec_key_deriver.cpp \ oec_session_util.cpp \ oemcrypto_corpus_generator_helper.cpp \ oemcrypto_session_tests_helper.cpp \ + oemcrypto_basic_test.cpp \ + oemcrypto_decrypt_test.cpp \ + oemcrypto_license_test.cpp \ + oemcrypto_provisioning_test.cpp \ + oemcrypto_usage_table_test.cpp \ oemcrypto_test.cpp \ oemcrypto_test_android.cpp \ oemcrypto_test_main.cpp \ @@ -46,11 +43,13 @@ LOCAL_C_INCLUDES += \ LOCAL_STATIC_LIBRARIES := \ libcdm \ + libjsmn \ + libgmock \ libgtest \ libgtest_main \ libwvlevel3 \ libcdm_protos \ - libcdm_utils_hidl \ + libcdm_utils \ libwv_kdo \ libwv_odk \ @@ -58,7 +57,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcrypto \ libdl \ - libhidlbase \ + libbinder_ndk \ liblog \ libmedia_omx \ libprotobuf-cpp-lite \ diff --git a/oemcrypto/test/fuzz_tests/README.md b/oemcrypto/test/fuzz_tests/README.md index 3f66444..e1b7b9c 100644 --- a/oemcrypto/test/fuzz_tests/README.md +++ b/oemcrypto/test/fuzz_tests/README.md @@ -23,7 +23,7 @@ OEMCrypto implementations on linux. The options to select are `Job type: libfuzzer_asan_oemcrypto` and `Fuzzer: fuzzer name you are looking for` - Example: [load_license_fuzz](https://clusterfuzz.corp.google.com/fuzzer-stats?group_by=by-day&date_start=2020-07-11&date_end=2020-07-17&fuzzer=libFuzzer_oemcrypto_load_license_fuzz&job=libfuzzer_asan_oemcrypto) + Example: [load_license_fuzz](https://clusterfuzz.corp.google.com/fuzzer-stats?group_by=by-day&date_start=2022-07-11&date_end=2022-07-17&fuzzer=libFuzzer_oemcrypto_load_license_fuzz&job=libfuzzer_asan_oemcrypto) ### Issues filed by clusterfuzz - Fixing those issues @@ -127,8 +127,7 @@ OEMCrypto implementations on linux. information locally. * Build and test fuzz scripts locally using following commands. The build - script builds fuzz binaries for both oemcrypto reference implementation - as well as opk implementation. + script builds fuzz binaries for opk implementation. ```shell $ cd PATH_TO_CDM_DIR diff --git a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests index 2b8c902..249616b 100755 --- a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests +++ b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests @@ -6,19 +6,23 @@ set -ex +# CDM_DIR is used by several script, especially when there is some confusion +if [ -z "$CDM_DIR" ]; then + export CDM_DIR="$(readlink -e $(dirname $0)/../../..)" +fi +cd $CDM_DIR + export CXX=clang++ export CC=clang export GYP_DEFINES="$GYP_DEFINES clang=1" -export PATH_TO_CDM_DIR=. -export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party" +echo "CDM_DIR = $CDM_DIR" +export PYTHONPATH="$PYTHONPATH:$CDM_DIR/third_party" -python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ - --depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp -ninja -C out/Default # oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets # with fuzzer flags. -python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ +python3 $CDM_DIR/third_party/gyp/__init__.py --format=ninja \ --depth=$(pwd) \ --include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \ + -Dopk_config_dir=$CDM_DIR/oemcrypto/opk/ports/linux/ta/common \ oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp ninja -C out/Default diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/0c7e14c42a24845ff54356b92cc20a3f9e2e6498 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/0c7e14c42a24845ff54356b92cc20a3f9e2e6498 new file mode 100644 index 0000000..cb306f7 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/0c7e14c42a24845ff54356b92cc20a3f9e2e6498 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 deleted file mode 100644 index 3c2447f..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/5812ad7753622d9177a1b3dd71c6c4a008ff54eb b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/5812ad7753622d9177a1b3dd71c6c4a008ff54eb deleted file mode 100644 index 46c70c7..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/5812ad7753622d9177a1b3dd71c6c4a008ff54eb and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/d936772829ba7bfac4b239053fcb7a622ff81203 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/d936772829ba7bfac4b239053fcb7a622ff81203 new file mode 100644 index 0000000..b73bdf8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/d936772829ba7bfac4b239053fcb7a622ff81203 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/fb094d421ad8099a07a15ae71060746b5ebcb129 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/fb094d421ad8099a07a15ae71060746b5ebcb129 new file mode 100644 index 0000000..60e15f8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/fb094d421ad8099a07a15ae71060746b5ebcb129 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0020aada9920cca0f1ca3bba3835c57ba1b64722 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0020aada9920cca0f1ca3bba3835c57ba1b64722 new file mode 100644 index 0000000..0d99959 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0020aada9920cca0f1ca3bba3835c57ba1b64722 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/00d8703220de64723c9508d6fad24e9caca9b67c b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/00d8703220de64723c9508d6fad24e9caca9b67c new file mode 100644 index 0000000..8a927ab Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/00d8703220de64723c9508d6fad24e9caca9b67c differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/01940cb7d91a0378062e3c34c6959c08cc64bfa7 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/01940cb7d91a0378062e3c34c6959c08cc64bfa7 new file mode 100644 index 0000000..8132496 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/01940cb7d91a0378062e3c34c6959c08cc64bfa7 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/02485b2bb1c97020e704aed055050a00d02362db b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/02485b2bb1c97020e704aed055050a00d02362db new file mode 100644 index 0000000..c37fec2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/02485b2bb1c97020e704aed055050a00d02362db differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/03ddc96089c172b96ea359aa658b103e711b0824 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/03ddc96089c172b96ea359aa658b103e711b0824 new file mode 100644 index 0000000..1a8ffc5 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/03ddc96089c172b96ea359aa658b103e711b0824 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/04124cff8b8ddc8f4f245b86f054d21bf6bf1118 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/04124cff8b8ddc8f4f245b86f054d21bf6bf1118 new file mode 100644 index 0000000..e39f530 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/04124cff8b8ddc8f4f245b86f054d21bf6bf1118 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0554387fba557ee5ad1222e62162d23733e507aa b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0554387fba557ee5ad1222e62162d23733e507aa new file mode 100644 index 0000000..79a0952 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0554387fba557ee5ad1222e62162d23733e507aa differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/06703ef82d4a6446b3f0008ab5240a8007769563 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/06703ef82d4a6446b3f0008ab5240a8007769563 new file mode 100644 index 0000000..615bf56 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/06703ef82d4a6446b3f0008ab5240a8007769563 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0b63f772494b90196d295375968a8da7f71add8c b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0b63f772494b90196d295375968a8da7f71add8c new file mode 100644 index 0000000..d0fe752 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0b63f772494b90196d295375968a8da7f71add8c differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0bb0b66fac20ba37c2858b7cc76c6af68b3c77a0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0bb0b66fac20ba37c2858b7cc76c6af68b3c77a0 new file mode 100644 index 0000000..425bc4a Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0bb0b66fac20ba37c2858b7cc76c6af68b3c77a0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0c3f5ede5008d158e079e71b676179175fcaf451 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0c3f5ede5008d158e079e71b676179175fcaf451 new file mode 100644 index 0000000..5f2ecf8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0c3f5ede5008d158e079e71b676179175fcaf451 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0ffae4ac0412685f5278d748bf45f78c25dbed10 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0ffae4ac0412685f5278d748bf45f78c25dbed10 new file mode 100644 index 0000000..44b4cd7 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/0ffae4ac0412685f5278d748bf45f78c25dbed10 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1094990c3689bc731ba000f7c144920750d254e3 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1094990c3689bc731ba000f7c144920750d254e3 new file mode 100644 index 0000000..5572991 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1094990c3689bc731ba000f7c144920750d254e3 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/10da8c370429a6a450d5ad0ee563653d18dbfeb8 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/10da8c370429a6a450d5ad0ee563653d18dbfeb8 deleted file mode 100644 index 129e7c5..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/10da8c370429a6a450d5ad0ee563653d18dbfeb8 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1262bc5f3f1ecc414e8e21861e9d200c3b775e87 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1262bc5f3f1ecc414e8e21861e9d200c3b775e87 new file mode 100644 index 0000000..ac50bf8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1262bc5f3f1ecc414e8e21861e9d200c3b775e87 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/137d434df4e17271af719ad678e7e74edc284f18 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/137d434df4e17271af719ad678e7e74edc284f18 new file mode 100644 index 0000000..7663081 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/137d434df4e17271af719ad678e7e74edc284f18 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/13bdd5f2dbf82567a92c2a30b9ef2310a02af361 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/13bdd5f2dbf82567a92c2a30b9ef2310a02af361 new file mode 100644 index 0000000..c8c042e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/13bdd5f2dbf82567a92c2a30b9ef2310a02af361 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1539088d12d235bba441c8fb46b54d839110cc38 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1539088d12d235bba441c8fb46b54d839110cc38 new file mode 100644 index 0000000..823f50c Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1539088d12d235bba441c8fb46b54d839110cc38 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/17cf1e48c441638a2874088ac78b42e8c4cca286 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/17cf1e48c441638a2874088ac78b42e8c4cca286 new file mode 100644 index 0000000..5762de6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/17cf1e48c441638a2874088ac78b42e8c4cca286 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/188bc9339e5b42687067e26369840c9eca20703f b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/188bc9339e5b42687067e26369840c9eca20703f new file mode 100644 index 0000000..de0284f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/188bc9339e5b42687067e26369840c9eca20703f differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1ae600c50a9a0bca685d7b83004fa3135901ded2 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1ae600c50a9a0bca685d7b83004fa3135901ded2 deleted file mode 100644 index 803d215..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1ae600c50a9a0bca685d7b83004fa3135901ded2 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1b40e1b853761bf6db5deac7df38532d8199aee5 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1b40e1b853761bf6db5deac7df38532d8199aee5 new file mode 100644 index 0000000..95784e7 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1b40e1b853761bf6db5deac7df38532d8199aee5 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1e148e9501ed59f5274e01ae905b2bf5db81ef79 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1e148e9501ed59f5274e01ae905b2bf5db81ef79 new file mode 100644 index 0000000..e636810 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1e148e9501ed59f5274e01ae905b2bf5db81ef79 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2001ea8811ed0ce164b49879561918ef3b43a78c b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2001ea8811ed0ce164b49879561918ef3b43a78c new file mode 100644 index 0000000..77f3762 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2001ea8811ed0ce164b49879561918ef3b43a78c differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 deleted file mode 100644 index f3c738d..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/22e370faf486d5e245dcc33671bbf15910a5e91e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/22e370faf486d5e245dcc33671bbf15910a5e91e new file mode 100644 index 0000000..6d6f168 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/22e370faf486d5e245dcc33671bbf15910a5e91e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/236647fd79907186bba5d42ebcc90e62ea632872 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/236647fd79907186bba5d42ebcc90e62ea632872 new file mode 100644 index 0000000..639397d Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/236647fd79907186bba5d42ebcc90e62ea632872 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2748bf06f5a71cc5f30fae9f957e537f39b2aa77 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2748bf06f5a71cc5f30fae9f957e537f39b2aa77 new file mode 100644 index 0000000..5ad09b6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2748bf06f5a71cc5f30fae9f957e537f39b2aa77 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2a0036c5d91f99392a7c334090fcbab08a6fcdb1 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2a0036c5d91f99392a7c334090fcbab08a6fcdb1 new file mode 100644 index 0000000..f14e71d Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2a0036c5d91f99392a7c334090fcbab08a6fcdb1 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2aba87702e45624da9e76eb525b469231c67d5cf b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2aba87702e45624da9e76eb525b469231c67d5cf new file mode 100644 index 0000000..77ccd5b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2aba87702e45624da9e76eb525b469231c67d5cf differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2bacc4d5c23a6eedcf6781480e31a36022ca5962 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2bacc4d5c23a6eedcf6781480e31a36022ca5962 new file mode 100644 index 0000000..2e0c3f5 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2bacc4d5c23a6eedcf6781480e31a36022ca5962 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2d611b2f63d41a650304b2b6712496b8392c2659 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2d611b2f63d41a650304b2b6712496b8392c2659 new file mode 100644 index 0000000..60ada77 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2d611b2f63d41a650304b2b6712496b8392c2659 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2dd14c72951c6ee8245c7e8d77a15eaec5d9839a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2dd14c72951c6ee8245c7e8d77a15eaec5d9839a new file mode 100644 index 0000000..a63d947 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/2dd14c72951c6ee8245c7e8d77a15eaec5d9839a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/308ecc136d6de9918abf890eef199d04df5bb2bb b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/308ecc136d6de9918abf890eef199d04df5bb2bb new file mode 100644 index 0000000..a6546e4 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/308ecc136d6de9918abf890eef199d04df5bb2bb differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3131b2f1c4628f9a979eb6f01861d75382f7273d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3131b2f1c4628f9a979eb6f01861d75382f7273d new file mode 100644 index 0000000..45a9b93 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3131b2f1c4628f9a979eb6f01861d75382f7273d differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/348418909f835c0728dd2317f5117ec38fc1be08 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/348418909f835c0728dd2317f5117ec38fc1be08 new file mode 100644 index 0000000..9e8f564 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/348418909f835c0728dd2317f5117ec38fc1be08 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34aed6ffd3161dc96341772a0b081095fed4821a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34aed6ffd3161dc96341772a0b081095fed4821a new file mode 100644 index 0000000..0016eb4 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34aed6ffd3161dc96341772a0b081095fed4821a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34d51b3476208e187a14dbbea713c48e72eaca35 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34d51b3476208e187a14dbbea713c48e72eaca35 new file mode 100644 index 0000000..eae55b2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/34d51b3476208e187a14dbbea713c48e72eaca35 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/35fe27def9bffe7aaca02f2d326b1109bd2c53e2 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/35fe27def9bffe7aaca02f2d326b1109bd2c53e2 new file mode 100644 index 0000000..964189c Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/35fe27def9bffe7aaca02f2d326b1109bd2c53e2 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/36e2425af5b4a62301e9ebfbf70f9e28e8a39f3e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/36e2425af5b4a62301e9ebfbf70f9e28e8a39f3e new file mode 100644 index 0000000..33b4d53 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/36e2425af5b4a62301e9ebfbf70f9e28e8a39f3e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38d4821122ddf0e84dba312f444bfbef5b81cc9d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38d4821122ddf0e84dba312f444bfbef5b81cc9d deleted file mode 100644 index deaea68..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38d4821122ddf0e84dba312f444bfbef5b81cc9d and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38f06ab2029f7317904acba919fabdf25edc02ff b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38f06ab2029f7317904acba919fabdf25edc02ff new file mode 100644 index 0000000..5db4a6d Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38f06ab2029f7317904acba919fabdf25edc02ff differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3abaedec5d45b91330b60a338f56906218ca1cbc b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3abaedec5d45b91330b60a338f56906218ca1cbc new file mode 100644 index 0000000..6d191a5 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3abaedec5d45b91330b60a338f56906218ca1cbc differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cab0134e48bd02f3262515075806ebc5502b0cc b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cab0134e48bd02f3262515075806ebc5502b0cc new file mode 100644 index 0000000..e3d8992 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cab0134e48bd02f3262515075806ebc5502b0cc differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cd9a833ced641a1716ca14082589ce7ce2cbbb0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cd9a833ced641a1716ca14082589ce7ce2cbbb0 new file mode 100644 index 0000000..2de08c6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cd9a833ced641a1716ca14082589ce7ce2cbbb0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cdf5d3cd5937b78d2560970a0ccce14fb0d0230 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cdf5d3cd5937b78d2560970a0ccce14fb0d0230 deleted file mode 100644 index 1daaa24..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cdf5d3cd5937b78d2560970a0ccce14fb0d0230 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 deleted file mode 100644 index 30e8810..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 deleted file mode 100644 index 66ff92c..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4191139fe9afc02615ba9159bd3d35b6d6a7d073 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4191139fe9afc02615ba9159bd3d35b6d6a7d073 new file mode 100644 index 0000000..9f060a6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4191139fe9afc02615ba9159bd3d35b6d6a7d073 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4227fd95d3dc45067dc19e80c31eaf293c8afbee b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4227fd95d3dc45067dc19e80c31eaf293c8afbee new file mode 100644 index 0000000..a51590a Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4227fd95d3dc45067dc19e80c31eaf293c8afbee differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/446ee48d8665b10ab1c51b4bb98c832d9fbd9d3a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/446ee48d8665b10ab1c51b4bb98c832d9fbd9d3a new file mode 100644 index 0000000..dc366ff Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/446ee48d8665b10ab1c51b4bb98c832d9fbd9d3a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4609e29ba8ece69cc08f7d93093768d9d3d959e4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4609e29ba8ece69cc08f7d93093768d9d3d959e4 new file mode 100644 index 0000000..01a1100 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4609e29ba8ece69cc08f7d93093768d9d3d959e4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/478e8789ac549a52ab303897c03676879ba014e2 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/478e8789ac549a52ab303897c03676879ba014e2 new file mode 100644 index 0000000..2a433e7 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/478e8789ac549a52ab303897c03676879ba014e2 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/494214feb44b57cb9e592c1ed220e87e0809db86 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/494214feb44b57cb9e592c1ed220e87e0809db86 new file mode 100644 index 0000000..141e743 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/494214feb44b57cb9e592c1ed220e87e0809db86 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a188fb2e329657694813f19d00d2634818ba22b b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a188fb2e329657694813f19d00d2634818ba22b new file mode 100644 index 0000000..60c2347 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a188fb2e329657694813f19d00d2634818ba22b differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a5bc3e146138236be11224681b998194ec1ff9a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a5bc3e146138236be11224681b998194ec1ff9a new file mode 100644 index 0000000..af793db Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4a5bc3e146138236be11224681b998194ec1ff9a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4d0abf7562348a077076a31f67dab240996227e6 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4d0abf7562348a077076a31f67dab240996227e6 new file mode 100644 index 0000000..9afe3b6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4d0abf7562348a077076a31f67dab240996227e6 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e6ba7bcb6b209ae89e33fca8b04458f21983df0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e6ba7bcb6b209ae89e33fca8b04458f21983df0 new file mode 100644 index 0000000..237097b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e6ba7bcb6b209ae89e33fca8b04458f21983df0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e751fabb40fc3d2cd82d80acda4a60d3bffda45 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e751fabb40fc3d2cd82d80acda4a60d3bffda45 new file mode 100644 index 0000000..4e0d351 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/4e751fabb40fc3d2cd82d80acda4a60d3bffda45 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/53a0b89316eedbd09f44336f493067c223d3afa0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/53a0b89316eedbd09f44336f493067c223d3afa0 new file mode 100644 index 0000000..8ffedfa Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/53a0b89316eedbd09f44336f493067c223d3afa0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/541a0b0c26a07b77109da181a00b0cc0e3b6c6c0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/541a0b0c26a07b77109da181a00b0cc0e3b6c6c0 new file mode 100644 index 0000000..3169e31 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/541a0b0c26a07b77109da181a00b0cc0e3b6c6c0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5745eabb985db8f6c6cd44f6bfbdccf2c3d69c08 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5745eabb985db8f6c6cd44f6bfbdccf2c3d69c08 new file mode 100644 index 0000000..dcd345a Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5745eabb985db8f6c6cd44f6bfbdccf2c3d69c08 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/58750d3a6ae389e16bab9c8a5eb8f444d4822a56 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/58750d3a6ae389e16bab9c8a5eb8f444d4822a56 new file mode 100644 index 0000000..83302c1 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/58750d3a6ae389e16bab9c8a5eb8f444d4822a56 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/596a7741bc1da115af7b9a5d9a38fdf109b7fcfc b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/596a7741bc1da115af7b9a5d9a38fdf109b7fcfc new file mode 100644 index 0000000..14b60cb Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/596a7741bc1da115af7b9a5d9a38fdf109b7fcfc differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/59ca33a53cdcd43ca7bcfa317e6baa9e9274d5c4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/59ca33a53cdcd43ca7bcfa317e6baa9e9274d5c4 new file mode 100644 index 0000000..224e422 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/59ca33a53cdcd43ca7bcfa317e6baa9e9274d5c4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5bd6daea2290abd4fd85fb7fc4ef767d0c31d59a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5bd6daea2290abd4fd85fb7fc4ef767d0c31d59a new file mode 100644 index 0000000..21e51bd Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5bd6daea2290abd4fd85fb7fc4ef767d0c31d59a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5ca0f3fcea25b2a8558315a52ed7ec10b31c8a06 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5ca0f3fcea25b2a8558315a52ed7ec10b31c8a06 new file mode 100644 index 0000000..67f7fa3 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5ca0f3fcea25b2a8558315a52ed7ec10b31c8a06 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5d0f9ef8f9bb3ddd53f5fb90bb91b69dd76c7967 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5d0f9ef8f9bb3ddd53f5fb90bb91b69dd76c7967 new file mode 100644 index 0000000..5e7065b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5d0f9ef8f9bb3ddd53f5fb90bb91b69dd76c7967 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5f77b862460a773e87eca1a72d6ec68ed3a6b9db b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5f77b862460a773e87eca1a72d6ec68ed3a6b9db new file mode 100644 index 0000000..ba15742 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/5f77b862460a773e87eca1a72d6ec68ed3a6b9db differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6240d30abd265d95c08193edecbc06900eafbc92 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6240d30abd265d95c08193edecbc06900eafbc92 new file mode 100644 index 0000000..d40c3a2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6240d30abd265d95c08193edecbc06900eafbc92 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/62a11e2f3482935ce23d81fa268c0094d5ad58e6 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/62a11e2f3482935ce23d81fa268c0094d5ad58e6 new file mode 100644 index 0000000..9fab967 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/62a11e2f3482935ce23d81fa268c0094d5ad58e6 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/634cbe7377cbd3358e239c185ccb6a4a78be3f27 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/634cbe7377cbd3358e239c185ccb6a4a78be3f27 new file mode 100644 index 0000000..d186132 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/634cbe7377cbd3358e239c185ccb6a4a78be3f27 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/638c5864a20d1ca04ad06d3a77181479f477ee91 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/638c5864a20d1ca04ad06d3a77181479f477ee91 new file mode 100644 index 0000000..434048c Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/638c5864a20d1ca04ad06d3a77181479f477ee91 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/67cd7db5d431fb1c35f96b0e8ce416d61cbfaa8b b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/67cd7db5d431fb1c35f96b0e8ce416d61cbfaa8b new file mode 100644 index 0000000..a41a924 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/67cd7db5d431fb1c35f96b0e8ce416d61cbfaa8b differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/69ba9c487a8b2d6c4812a9a39d9e069265be4afa b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/69ba9c487a8b2d6c4812a9a39d9e069265be4afa new file mode 100644 index 0000000..549b3ff Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/69ba9c487a8b2d6c4812a9a39d9e069265be4afa differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6af75aec999c45b84de4d3247f791f1a63c4afe9 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6af75aec999c45b84de4d3247f791f1a63c4afe9 new file mode 100644 index 0000000..18c87c2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6af75aec999c45b84de4d3247f791f1a63c4afe9 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6d0ee80399e88ffdb1778b0bae7b6605c099c2f6 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6d0ee80399e88ffdb1778b0bae7b6605c099c2f6 new file mode 100644 index 0000000..eec9883 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6d0ee80399e88ffdb1778b0bae7b6605c099c2f6 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6f65463040c50e026e252e7544dff41babbc4604 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6f65463040c50e026e252e7544dff41babbc4604 deleted file mode 100644 index a7629af..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6f65463040c50e026e252e7544dff41babbc4604 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/73606d355e70125052bd75183dc0fbc658238788 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/73606d355e70125052bd75183dc0fbc658238788 new file mode 100644 index 0000000..dc243da Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/73606d355e70125052bd75183dc0fbc658238788 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/736dde51d09a2c4ff85d7b559d08176c951b07c8 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/736dde51d09a2c4ff85d7b559d08176c951b07c8 new file mode 100644 index 0000000..820d188 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/736dde51d09a2c4ff85d7b559d08176c951b07c8 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/737cd5853708e2d2732e4c54dc944bc54d522406 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/737cd5853708e2d2732e4c54dc944bc54d522406 deleted file mode 100644 index 93bed59..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/737cd5853708e2d2732e4c54dc944bc54d522406 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/74395b056ddfc22160234e4a4616bf87e2159eda b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/74395b056ddfc22160234e4a4616bf87e2159eda new file mode 100644 index 0000000..85d1c76 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/74395b056ddfc22160234e4a4616bf87e2159eda differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7530e1b5149d2f3931560cbecfa27895179fd279 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7530e1b5149d2f3931560cbecfa27895179fd279 new file mode 100644 index 0000000..f9e2071 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7530e1b5149d2f3931560cbecfa27895179fd279 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7691d3426449d4e2262b58f6be2c1018cd6d2e5f b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7691d3426449d4e2262b58f6be2c1018cd6d2e5f new file mode 100644 index 0000000..545195d Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7691d3426449d4e2262b58f6be2c1018cd6d2e5f differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/790c61aca1614bd78a71ffd715b0498d2518dcd8 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/790c61aca1614bd78a71ffd715b0498d2518dcd8 new file mode 100644 index 0000000..6ed97e9 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/790c61aca1614bd78a71ffd715b0498d2518dcd8 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7af21f77c85a086490b6447bcd70b2844b68101c b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7af21f77c85a086490b6447bcd70b2844b68101c new file mode 100644 index 0000000..dfe1b8f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7af21f77c85a086490b6447bcd70b2844b68101c differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7c440058b109a6456c50bfc87cbbebd0360e51a0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7c440058b109a6456c50bfc87cbbebd0360e51a0 new file mode 100644 index 0000000..12c1f4e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7c440058b109a6456c50bfc87cbbebd0360e51a0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7cf33864cf4435593d27b9c4ca8974cfa5c9d7d7 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7cf33864cf4435593d27b9c4ca8974cfa5c9d7d7 new file mode 100644 index 0000000..7feed16 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7cf33864cf4435593d27b9c4ca8974cfa5c9d7d7 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7e55089df762082a4d8d905f5cb1ef27d976eb38 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7e55089df762082a4d8d905f5cb1ef27d976eb38 new file mode 100644 index 0000000..3418fcf Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/7e55089df762082a4d8d905f5cb1ef27d976eb38 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/81dbdffe5f44dcae32cd958cbe8f3f451819d07a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/81dbdffe5f44dcae32cd958cbe8f3f451819d07a new file mode 100644 index 0000000..ed02f5b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/81dbdffe5f44dcae32cd958cbe8f3f451819d07a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/82b8a9f56e65b3e2af929c4d62d95e7768850eb4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/82b8a9f56e65b3e2af929c4d62d95e7768850eb4 new file mode 100644 index 0000000..c36fbc5 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/82b8a9f56e65b3e2af929c4d62d95e7768850eb4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8483cbe550b4c9343c3361935bc8d3a7c30b3ece b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8483cbe550b4c9343c3361935bc8d3a7c30b3ece new file mode 100644 index 0000000..cbb8c60 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8483cbe550b4c9343c3361935bc8d3a7c30b3ece differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/84c5d943ba95108d4072c7843df631bcbd177391 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/84c5d943ba95108d4072c7843df631bcbd177391 new file mode 100644 index 0000000..f34be3e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/84c5d943ba95108d4072c7843df631bcbd177391 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/86638a56e2496c3c8cd2750db9b912956daaed1f b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/86638a56e2496c3c8cd2750db9b912956daaed1f new file mode 100644 index 0000000..fc7d9a4 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/86638a56e2496c3c8cd2750db9b912956daaed1f differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/892a862becababdcb28d2a893f3a2ce01abc16e4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/892a862becababdcb28d2a893f3a2ce01abc16e4 new file mode 100644 index 0000000..1cf5fa5 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/892a862becababdcb28d2a893f3a2ce01abc16e4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8b15a9c75b3043040a90f28e84de28e436e023d7 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8b15a9c75b3043040a90f28e84de28e436e023d7 new file mode 100644 index 0000000..980fd4f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8b15a9c75b3043040a90f28e84de28e436e023d7 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8eeffea9e7c3876ffc477ce68a3c0ac4375ef3aa b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8eeffea9e7c3876ffc477ce68a3c0ac4375ef3aa new file mode 100644 index 0000000..01d7ba6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/8eeffea9e7c3876ffc477ce68a3c0ac4375ef3aa differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/901e4c6087322b69946ec8dd8d9fa401eebc826f b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/901e4c6087322b69946ec8dd8d9fa401eebc826f new file mode 100644 index 0000000..0790556 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/901e4c6087322b69946ec8dd8d9fa401eebc826f differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/950e3521352f0c27063a87618a490346f0a3c2f4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/950e3521352f0c27063a87618a490346f0a3c2f4 new file mode 100644 index 0000000..cf62735 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/950e3521352f0c27063a87618a490346f0a3c2f4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/97034a7defd7d47912f2353de7e816382562f038 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/97034a7defd7d47912f2353de7e816382562f038 new file mode 100644 index 0000000..5470012 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/97034a7defd7d47912f2353de7e816382562f038 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9df1116c393c752cd6640ae70709774d6bb96f37 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9df1116c393c752cd6640ae70709774d6bb96f37 new file mode 100644 index 0000000..85d7c43 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9df1116c393c752cd6640ae70709774d6bb96f37 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e09a35f73eab1946a6b0db676e913c41222942a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e09a35f73eab1946a6b0db676e913c41222942a new file mode 100644 index 0000000..7f1cd0a Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e09a35f73eab1946a6b0db676e913c41222942a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e490b158b6fc8ec4642f4ae51e0b9afbe2e4925 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e490b158b6fc8ec4642f4ae51e0b9afbe2e4925 new file mode 100644 index 0000000..bb8ba9d Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9e490b158b6fc8ec4642f4ae51e0b9afbe2e4925 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9f05626c0ea01489c75f0493ec02c973098a3d41 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9f05626c0ea01489c75f0493ec02c973098a3d41 new file mode 100644 index 0000000..8c8cf46 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/9f05626c0ea01489c75f0493ec02c973098a3d41 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a0cf2b857c3f281595d4eae2b0a95dfeac5659ce b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a0cf2b857c3f281595d4eae2b0a95dfeac5659ce new file mode 100644 index 0000000..469a399 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a0cf2b857c3f281595d4eae2b0a95dfeac5659ce differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a94aa8ced89b824652465e60330e474dc5a5ac15 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a94aa8ced89b824652465e60330e474dc5a5ac15 new file mode 100644 index 0000000..cbd77d8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a94aa8ced89b824652465e60330e474dc5a5ac15 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a99f51d8c51e9e70c6f5ef45702379aace415853 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a99f51d8c51e9e70c6f5ef45702379aace415853 new file mode 100644 index 0000000..f78544f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/a99f51d8c51e9e70c6f5ef45702379aace415853 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ac592ee43e003afa088bb5effbdc4679476e06a5 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ac592ee43e003afa088bb5effbdc4679476e06a5 new file mode 100644 index 0000000..d521dad Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ac592ee43e003afa088bb5effbdc4679476e06a5 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/adab987e21e9838b02e500658ea0818a18ac0403 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/adab987e21e9838b02e500658ea0818a18ac0403 new file mode 100644 index 0000000..77d070f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/adab987e21e9838b02e500658ea0818a18ac0403 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ade91aa40b8684929b4f3fe13632a09335f0767c b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ade91aa40b8684929b4f3fe13632a09335f0767c new file mode 100644 index 0000000..dcd9da2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ade91aa40b8684929b4f3fe13632a09335f0767c differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0405d219290369a7507d9a9a4096209855ece5b b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0405d219290369a7507d9a9a4096209855ece5b new file mode 100644 index 0000000..b2a1d17 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0405d219290369a7507d9a9a4096209855ece5b differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0de353b0ff4b2dfbaba3574f6e84dcdf1b01d7d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0de353b0ff4b2dfbaba3574f6e84dcdf1b01d7d new file mode 100644 index 0000000..3a6abd3 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b0de353b0ff4b2dfbaba3574f6e84dcdf1b01d7d differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b33349107da622826c0de5883dfd2bc8adfb51f5 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b33349107da622826c0de5883dfd2bc8adfb51f5 new file mode 100644 index 0000000..a1c1bd1 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b33349107da622826c0de5883dfd2bc8adfb51f5 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b3554fe52837e96c0477f59c4574925959fa73b8 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b3554fe52837e96c0477f59c4574925959fa73b8 new file mode 100644 index 0000000..ffa2806 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/b3554fe52837e96c0477f59c4574925959fa73b8 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/baf88bf2463826c84b748aabdce12a406870f43a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/baf88bf2463826c84b748aabdce12a406870f43a new file mode 100644 index 0000000..f93d377 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/baf88bf2463826c84b748aabdce12a406870f43a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bcf58b9cf74875a7b938460b19e703876c2b3067 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bcf58b9cf74875a7b938460b19e703876c2b3067 new file mode 100644 index 0000000..cb20ada Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bcf58b9cf74875a7b938460b19e703876c2b3067 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bd2a9a445ebf80d33d947a94ef007d9da69fdd63 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bd2a9a445ebf80d33d947a94ef007d9da69fdd63 new file mode 100644 index 0000000..d5def68 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bd2a9a445ebf80d33d947a94ef007d9da69fdd63 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/be836532b3c69821faecb2ee70da56687e442c36 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/be836532b3c69821faecb2ee70da56687e442c36 new file mode 100644 index 0000000..ff7e493 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/be836532b3c69821faecb2ee70da56687e442c36 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bf813f09576ef5dc365d4fae65be63a3c14c2de0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bf813f09576ef5dc365d4fae65be63a3c14c2de0 new file mode 100644 index 0000000..4f1359c Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/bf813f09576ef5dc365d4fae65be63a3c14c2de0 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c04f75d30fdacb872a5bd369634ee4de4267661e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c04f75d30fdacb872a5bd369634ee4de4267661e new file mode 100644 index 0000000..bd53ae6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c04f75d30fdacb872a5bd369634ee4de4267661e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2ab467b1f82ebbb4a595a34ed4688640acd67db b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2ab467b1f82ebbb4a595a34ed4688640acd67db new file mode 100644 index 0000000..5d84ede Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2ab467b1f82ebbb4a595a34ed4688640acd67db differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2cf6eb87d09bcad3662b2352c1e23d1e4765f46 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2cf6eb87d09bcad3662b2352c1e23d1e4765f46 new file mode 100644 index 0000000..48b7921 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c2cf6eb87d09bcad3662b2352c1e23d1e4765f46 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c46552eb7f6937cb598ae6ffc76964f7ae2364bc b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c46552eb7f6937cb598ae6ffc76964f7ae2364bc new file mode 100644 index 0000000..0479bf7 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c46552eb7f6937cb598ae6ffc76964f7ae2364bc differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c5ebff5a561cbc77637919c5235a95246c755c15 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c5ebff5a561cbc77637919c5235a95246c755c15 new file mode 100644 index 0000000..fa86f79 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c5ebff5a561cbc77637919c5235a95246c755c15 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c613e9ab2b629c7b897975460e5c33e8ac1a2232 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c613e9ab2b629c7b897975460e5c33e8ac1a2232 new file mode 100644 index 0000000..b504855 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c613e9ab2b629c7b897975460e5c33e8ac1a2232 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c87d77a256014f0e9f443230be3cadf84b842da5 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c87d77a256014f0e9f443230be3cadf84b842da5 new file mode 100644 index 0000000..eb9a62b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/c87d77a256014f0e9f443230be3cadf84b842da5 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/cd0ed0742b01b47f64707b0ceae55e4bddc8a53e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/cd0ed0742b01b47f64707b0ceae55e4bddc8a53e new file mode 100644 index 0000000..543669b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/cd0ed0742b01b47f64707b0ceae55e4bddc8a53e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d2f3a5ef8bb1964340a5fac8bdef3a1cbd919907 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d2f3a5ef8bb1964340a5fac8bdef3a1cbd919907 new file mode 100644 index 0000000..511f396 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d2f3a5ef8bb1964340a5fac8bdef3a1cbd919907 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d4a96cf0b53f7342e749a0791a513dbfaf6d4ccf b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d4a96cf0b53f7342e749a0791a513dbfaf6d4ccf new file mode 100644 index 0000000..986208e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d4a96cf0b53f7342e749a0791a513dbfaf6d4ccf differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d5cf79b024f393643248821250f7042caa74b33e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d5cf79b024f393643248821250f7042caa74b33e new file mode 100644 index 0000000..4a2e690 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d5cf79b024f393643248821250f7042caa74b33e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d775f9b5597e76cbf380ad74fea86c307c224309 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d775f9b5597e76cbf380ad74fea86c307c224309 deleted file mode 100644 index e6b86fa..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d775f9b5597e76cbf380ad74fea86c307c224309 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d77fa923d5ec1c125ca9347d1f97b24995737806 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d77fa923d5ec1c125ca9347d1f97b24995737806 new file mode 100644 index 0000000..64af970 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d77fa923d5ec1c125ca9347d1f97b24995737806 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7c21613ad6684dc73e1515178d0cfcbffea1df2 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7c21613ad6684dc73e1515178d0cfcbffea1df2 new file mode 100644 index 0000000..6aa20f3 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7c21613ad6684dc73e1515178d0cfcbffea1df2 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7ef40b0ea62d59bc4c8d1525aa3ee0ca5444532 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7ef40b0ea62d59bc4c8d1525aa3ee0ca5444532 new file mode 100644 index 0000000..cb2e13e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d7ef40b0ea62d59bc4c8d1525aa3ee0ca5444532 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d9833213bb3e03d7894ffb4016188d4afc4411b4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d9833213bb3e03d7894ffb4016188d4afc4411b4 new file mode 100644 index 0000000..095cb69 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d9833213bb3e03d7894ffb4016188d4afc4411b4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/db83511a3ced2c03600163abf429f3a68a2c419d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/db83511a3ced2c03600163abf429f3a68a2c419d new file mode 100644 index 0000000..c48ef81 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/db83511a3ced2c03600163abf429f3a68a2c419d differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/dd42a4c087d8e17e1dbabcba4e4bf48b98f3329f b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/dd42a4c087d8e17e1dbabcba4e4bf48b98f3329f new file mode 100644 index 0000000..8552bf1 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/dd42a4c087d8e17e1dbabcba4e4bf48b98f3329f differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1542bc7ccdc101ae6a8051e6460fd5005097f79 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1542bc7ccdc101ae6a8051e6460fd5005097f79 new file mode 100644 index 0000000..df259ac Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1542bc7ccdc101ae6a8051e6460fd5005097f79 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1d142ea43c04e41b757f01d8987dd6af069a463 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1d142ea43c04e41b757f01d8987dd6af069a463 new file mode 100644 index 0000000..4c749b8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e1d142ea43c04e41b757f01d8987dd6af069a463 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e3e502902e40348546d1352eaba467591b3df7f4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e3e502902e40348546d1352eaba467591b3df7f4 new file mode 100644 index 0000000..3a243d3 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e3e502902e40348546d1352eaba467591b3df7f4 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e43bf4879aa0837380a0d93342b30a193c4af677 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e43bf4879aa0837380a0d93342b30a193c4af677 new file mode 100644 index 0000000..c6ef4a6 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e43bf4879aa0837380a0d93342b30a193c4af677 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e564ac5e15a78f795629ab31a8a88e91898095a1 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e564ac5e15a78f795629ab31a8a88e91898095a1 new file mode 100644 index 0000000..15c9a7e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e564ac5e15a78f795629ab31a8a88e91898095a1 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e751c0f21a9ebccab51d453d0fe32f249e632070 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e751c0f21a9ebccab51d453d0fe32f249e632070 new file mode 100644 index 0000000..9bf92e2 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e751c0f21a9ebccab51d453d0fe32f249e632070 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e7d4d0e761252d3de02e3d5c9f98cbc4920ff445 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e7d4d0e761252d3de02e3d5c9f98cbc4920ff445 new file mode 100644 index 0000000..95374a4 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e7d4d0e761252d3de02e3d5c9f98cbc4920ff445 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e8216eb21330e411b6aca3fd6803bb61a7808483 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e8216eb21330e411b6aca3fd6803bb61a7808483 new file mode 100644 index 0000000..af2be3f Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e8216eb21330e411b6aca3fd6803bb61a7808483 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e914b2a8555bb893176180e01044325cfc2f8bf1 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e914b2a8555bb893176180e01044325cfc2f8bf1 new file mode 100644 index 0000000..b502858 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e914b2a8555bb893176180e01044325cfc2f8bf1 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 deleted file mode 100644 index d586f10..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce deleted file mode 100644 index a7dc614..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ef880a270034e0f210254f3f3574bca5cfe13b54 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ef880a270034e0f210254f3f3574bca5cfe13b54 new file mode 100644 index 0000000..f19a44e Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ef880a270034e0f210254f3f3574bca5cfe13b54 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f0950c0364b9ab5aa1aa584c183098f262817088 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f0950c0364b9ab5aa1aa584c183098f262817088 new file mode 100644 index 0000000..4c6aec8 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f0950c0364b9ab5aa1aa584c183098f262817088 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f2b4023c8bafb4c2423751ee5e070eca4026c050 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f2b4023c8bafb4c2423751ee5e070eca4026c050 new file mode 100644 index 0000000..d44c14b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f2b4023c8bafb4c2423751ee5e070eca4026c050 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f31d50d032713c24334c3ca21cffc16c5fa2cc0a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f31d50d032713c24334c3ca21cffc16c5fa2cc0a new file mode 100644 index 0000000..0cd2c5c Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f31d50d032713c24334c3ca21cffc16c5fa2cc0a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f4432c2a09512441123fd68f6ee3ede217067444 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f4432c2a09512441123fd68f6ee3ede217067444 new file mode 100644 index 0000000..3ffb03b Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f4432c2a09512441123fd68f6ee3ede217067444 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f61ea517b82990485bff8a973a91a717d1a6bf94 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f61ea517b82990485bff8a973a91a717d1a6bf94 new file mode 100644 index 0000000..d635eec Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f61ea517b82990485bff8a973a91a717d1a6bf94 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f6c28150e2e1a1390516a09d453d33cb9a1337b4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f6c28150e2e1a1390516a09d453d33cb9a1337b4 deleted file mode 100644 index b980096..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f6c28150e2e1a1390516a09d453d33cb9a1337b4 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f860eb559bcb2592b50273cf176aab4c624ab387 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f860eb559bcb2592b50273cf176aab4c624ab387 new file mode 100644 index 0000000..face2ba Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f860eb559bcb2592b50273cf176aab4c624ab387 differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ffc43d4749a49d8db8fb96d498a34bbb62af2e0e b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ffc43d4749a49d8db8fb96d498a34bbb62af2e0e new file mode 100644 index 0000000..48e5f63 Binary files /dev/null and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/ffc43d4749a49d8db8fb96d498a34bbb62af2e0e differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d deleted file mode 100644 index f5dc76e..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a94b2e9c5f7896643f5405d040cddacb15f8866a similarity index 63% rename from oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 rename to oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a94b2e9c5f7896643f5405d040cddacb15f8866a index 561fce2..9775e6c 100644 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a94b2e9c5f7896643f5405d040cddacb15f8866a differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 deleted file mode 100644 index 7a2af72..0000000 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 and /dev/null differ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/d1ef093f11c8e8c42da35501230bb7030067602e similarity index 62% rename from oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 rename to oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/d1ef093f11c8e8c42da35501230bb7030067602e index 2f041f7..6bdca2d 100644 Binary files a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 and b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/d1ef093f11c8e8c42da35501230bb7030067602e differ diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc index 26f48cd..b9a1ce8 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc @@ -2,93 +2,82 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" namespace wvoec { -// Free dynamic memory allocated by fuzzer script. -void FreeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - int* secure_fd) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - delete[] output_descriptor.buffer.clear.clear_buffer; - break; - } - case OEMCrypto_BufferType_Secure: { - OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, *secure_fd); - break; - } - case OEMCrypto_BufferType_Direct: { - break; - } - } -} - -bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - int* secure_fd, size_t input_buffer_size) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear.clear_buffer = - new OEMCrypto_SharedMemory[input_buffer_size]; - return true; - } - case OEMCrypto_BufferType_Secure: { - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_id, input_buffer_size, &output_descriptor, secure_fd); - return sts == OEMCrypto_SUCCESS; - } - case OEMCrypto_BufferType_Direct: { - return true; - } - } -} extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise RedirectStdoutToFile(); - uint8_t subsample_flags; // OEMCrypto_DestBufferDesc and a buffer from which data needs to be copied // are expected as inputs to copy buffer API. - // Input fuzzed data is interpreted as + // Input fuzzed data is interpreted as: // (OEMCrypto_DestBufferDesc | subsample_flags | input_buffer) - if (size <= sizeof(OEMCrypto_Copy_Buffer_Fuzz)) { + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + if (size < sizeof(fuzzed_structure)) { return 0; } - OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; - // Fuzz dest_buffer_desc. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_BufferType_MaxValue, &fuzzed_structure.dest_buffer_desc.type); + fuzzed_structure.dest_buffer_desc.buffer_config %= MAX_FUZZ_OUTPUT_LENGTH + 1; + const std::vector input_buffer = + fuzzed_data.ConsumeRemainingBytes(); OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Fuzz input buffer to be copied. - size_t input_buffer_size = size - sizeof(fuzzed_structure); + const uint32_t session_id = license_api_fuzz.session()->session_id(); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc dest_buffer_desc; int secure_fd = 0; - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size); + dest_buffer_desc.type = fuzzed_structure.dest_buffer_desc.type; + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + dest_buffer_desc.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_structure.dest_buffer_desc + .buffer_config]; + dest_buffer_desc.buffer.clear.clear_buffer_length = + fuzzed_structure.dest_buffer_desc.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_structure.dest_buffer_desc.buffer_config, + &dest_buffer_desc, &secure_fd) != OEMCrypto_SUCCESS) { + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + dest_buffer_desc.buffer.direct.is_video = + fuzzed_structure.dest_buffer_desc.buffer_config & 1; + break; } - OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure), - input_buffer_size, &fuzzed_structure.dest_buffer_desc, - subsample_flags); - FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc, - &secure_fd); + + OEMCrypto_CopyBuffer(session_id, input_buffer.data(), input_buffer.size(), + &dest_buffer_desc, fuzzed_structure.subsample_flags); + + // Free output buffer. + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + delete[] dest_buffer_desc.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &dest_buffer_desc, secure_fd); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + return 0; } -} // namespace wvoec \ No newline at end of file + +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_create_and_remove_entitled_key_session_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_create_and_remove_entitled_key_session_fuzz.cc new file mode 100644 index 0000000..952946e --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_create_and_remove_entitled_key_session_fuzz.cc @@ -0,0 +1,34 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" + +namespace wvoec { +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + if (size < sizeof(ODK_ParsedLicense) + sizeof(MessageData)) { + return 0; + } + OEMCryptoLicenseAPIFuzz license_api_fuzz; + license_api_fuzz.license_messages().set_license_type( + OEMCrypto_EntitlementLicense); + license_api_fuzz.license_messages().SignAndVerifyRequest(); + // Interpreting input fuzz data as unencrypted (core_response + license + // message data) from license server. + license_api_fuzz.license_messages().InjectFuzzedResponseData(data, size); + license_api_fuzz.license_messages().EncryptAndSignResponse(); + license_api_fuzz.license_messages().LoadResponse(); + + uint32_t key_session_id; + OEMCrypto_CreateEntitledKeySession(license_api_fuzz.session_id(), + &key_session_id); + + OEMCrypto_RemoveEntitledKeySession(key_session_id); + + return 0; +} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc index 560a172..0c96b6b 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc @@ -15,9 +15,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Open a session, create a usage entry. Session* session = entry.license_messages().session(); session->open(); - entry.InstallTestRSAKey(session); - session->GenerateNonce(); + entry.InstallTestDrmKey(session); session->CreateNewUsageEntry(); + session->GenerateNonce(); vector encrypted_usage_header; session->UpdateUsageEntry(&encrypted_usage_header); // LoadLicense sets the pst for usage entry. diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc index eb1465e..8ddef79 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc @@ -4,184 +4,169 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" +#include "oec_session_util.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_overflow.h" namespace wvoec { -const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; -// Free dynamic memory allocated by fuzzer script. -void FreeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_SampleDescription* sample_description, - size_t sample_index, int* secure_fd_array) { - for (size_t i = 0; i < sample_index; i++) { - OEMCrypto_DestBufferDesc fuzzed_output_descriptor = - sample_description[i].buffers.output_descriptor; - switch (fuzzed_output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - delete[] fuzzed_output_descriptor.buffer.clear.clear_buffer; - break; - } - case OEMCrypto_BufferType_Secure: { - OEMCrypto_FreeSecureBuffer(session_id, &fuzzed_output_descriptor, - secure_fd_array[i]); - break; - } - case OEMCrypto_BufferType_Direct: { - break; - } - } - } -} -// Function to initialize output buffer pointers by allocating memory. -// Limiting output buffer size to 5 MB as 4 MB is maximum size specified -// by resource rating tier documentation. -bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - size_t sample_index, - vector& secure_fd_array) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear.clear_buffer = - new OEMCrypto_SharedMemory[std::min( - MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.clear.clear_buffer_length)]; - return true; - } - case OEMCrypto_BufferType_Secure: { - int* secure_fd; - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_id, - std::min(MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.secure.secure_buffer_length), - &output_descriptor, secure_fd); - if (sts == OEMCrypto_SUCCESS) secure_fd_array[sample_index] = *secure_fd; - return sts == OEMCrypto_SUCCESS; - } - case OEMCrypto_BufferType_Direct: { - return true; - } - } -} +// Limit output buffer size to 5 MB as 4 MB is maximum size specified by +// resource rating tier documentation. +const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise RedirectStdoutToFile(); - size_t samples_length; // Split data using separator. - auto inputs = SplitInput(data, size); - if (inputs.size() < 2) { + const std::vector inputs = SplitFuzzedData(data, size); + if (inputs.size() < 3) { return 0; } + // Read cipher mode and pattern from fuzzed data. OEMCrypto_Decrypt_Cenc_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } - // Copy OEMCrypto_Decrypt_Cenc_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); - size_t remaining_size_for_samples = - inputs[0].size() - sizeof(fuzzed_structure); - // Initialize FDP structures to read data using inbuilt functions. - FuzzedDataProvider fuzzed_sample_data(data + sizeof(fuzzed_structure), - remaining_size_for_samples); - FuzzedDataProvider fuzzed_subsample_data(inputs[1].data(), inputs[1].size()); + // Allocate sample descriptions. + std::vector sample_descriptions( + fuzzed_data.remaining_bytes() / sizeof(OEMCrypto_SampleDescription_Fuzz)); - // Read subsamples from fuzzed data. - vector subsamples; - while (fuzzed_subsample_data.remaining_bytes() >= - sizeof(OEMCrypto_SubSampleDescription)) { - OEMCrypto_SubSampleDescription subsample; - fuzzed_subsample_data.ConsumeData(&subsample, - sizeof(OEMCrypto_SubSampleDescription)); - subsamples.push_back(subsample); - } - if (subsamples.size() == 0) { - return 0; - } + // Allocate input buffers for each sample description. + std::vector> input_buffers( + sample_descriptions.size()); - // Infer samples_length from fuzzed data. - size_t sample_description_size = sizeof(OEMCrypto_SampleDescription); - samples_length = - fuzzed_sample_data.remaining_bytes() / sample_description_size; - if (samples_length == 0) { - return 0; - } + // Allocate secure_fd values for secure buffers. + std::vector secure_fd_array(sample_descriptions.size()); - // Initialize sample_descriptions array. - vector sample_descriptions(samples_length); - // Create array to maintain secure_fd buffer values for secure buffers. - vector secure_fd_array(samples_length); + // Allocate subsamples for each sample description. + std::vector> subsamples( + sample_descriptions.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Copy samples from fuzzed data. - size_t input_subsample_index = 0; - size_t total_input_data_length = 0; - for (size_t i = 0; i < samples_length; i++) { - fuzzed_sample_data.ConsumeData(&sample_descriptions[i], - sample_description_size); + const uint32_t session_id = license_api_fuzz.session()->session_id(); + + // Free first given number of output buffers. + const auto FreeOutputBuffers = [&sample_descriptions, session_id, + &secure_fd_array](size_t num_buffers) { + for (size_t i = 0; i < num_buffers; i++) { + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + delete[] output_descriptor.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, + secure_fd_array[i]); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + } + }; + + // Prepare each sample description. + FuzzedDataProvider& sample_description_data = fuzzed_data; + FuzzedDataProvider input_buffer_data(inputs[1].data, inputs[1].size); + FuzzedDataProvider subsample_data(inputs[2].data, inputs[2].size); + for (size_t i = 0; i < sample_descriptions.size(); i++) { + // Read and normalize sample description fuzzed properties. + OEMCrypto_SampleDescription_Fuzz fuzzed_sample_description; + sample_description_data.ConsumeData(&fuzzed_sample_description, + sizeof(fuzzed_sample_description)); + fuzzed_sample_description.buffers.input_data_length %= + MAX_FUZZ_SAMPLE_SIZE + 1; ConvertDataToValidEnum( OEMCrypto_BufferType_MaxValue, - &sample_descriptions[i].buffers.output_descriptor.type); + &fuzzed_sample_description.buffers.output_descriptor.type); + fuzzed_sample_description.buffers.output_descriptor.buffer_config %= + MAX_FUZZ_SAMPLE_SIZE + 1; - // Copy random data into input sample data. Cap input data length at 5 MB, - // 1 MB higher than that described by resource rating tier. - total_input_data_length += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); - - // Copy sub sample data. - sample_descriptions[i].subsamples = &subsamples[input_subsample_index]; - if (OPK_AddOverflowUX(input_subsample_index, - sample_descriptions[i].subsamples_length, - &input_subsample_index)) { + // Read input data. + if (fuzzed_sample_description.buffers.input_data_length > + input_buffer_data.remaining_bytes()) { + FreeOutputBuffers(i); return 0; } - if (input_subsample_index > subsamples.size()) return 0; - } // Sample loop. + input_buffers[i] = input_buffer_data.ConsumeBytes( + fuzzed_sample_description.buffers.input_data_length); + sample_descriptions[i].buffers.input_data = input_buffers[i].data(); + sample_descriptions[i].buffers.input_data_length = input_buffers[i].size(); - // Allocate input/output buffers for each sample description. - vector input_buffer(total_input_data_length); - size_t input_buffer_index = 0; - for (size_t i = 0; i < samples_length; i++) { - sample_descriptions[i].buffers.input_data = - &input_buffer[input_buffer_index]; - input_buffer_index += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); + // Set subsample data. + if (fuzzed_sample_description.subsamples_length > + subsample_data.remaining_bytes() / + sizeof(OEMCrypto_SubSampleDescription)) { + FreeOutputBuffers(i); + return 0; + } + if (fuzzed_sample_description.subsamples_length > 0) { + subsamples[i].resize(fuzzed_sample_description.subsamples_length); + subsample_data.ConsumeData( + subsamples[i].data(), + subsamples[i].size() * sizeof(OEMCrypto_SubSampleDescription)); + } + sample_descriptions[i].subsamples = subsamples[i].data(); + sample_descriptions[i].subsamples_length = subsamples[i].size(); - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers( - session->session_id(), - sample_descriptions[i].buffers.output_descriptor, i, - secure_fd_array)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - sample_descriptions[i].buffers.output_descriptor.type = - OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - sample_descriptions[i].buffers.output_descriptor, - i, secure_fd_array); + // Set IV data. + memcpy(sample_descriptions[i].iv, fuzzed_sample_description.iv, + sizeof(sample_descriptions[i].iv)); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + const OEMCrypto_DestBufferDesc_Fuzz& fuzzed_output_descriptor = + fuzzed_sample_description.buffers.output_descriptor; + output_descriptor.type = fuzzed_output_descriptor.type; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + output_descriptor.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_output_descriptor.buffer_config]; + output_descriptor.buffer.clear.clear_buffer_length = + fuzzed_output_descriptor.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_output_descriptor.buffer_config, + &output_descriptor, &secure_fd_array[i]) != OEMCrypto_SUCCESS) { + FreeOutputBuffers(i); + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + output_descriptor.buffer.direct.is_video = + fuzzed_output_descriptor.buffer_config & 1; + break; } } // Load license and call decrypt_cenc API. license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - fuzzed_structure.cipher_mode); - OEMCrypto_DecryptCENC(session->session_id(), sample_descriptions.data(), - samples_length, &fuzzed_structure.pattern); - FreeOutputBuffers(session->session_id(), sample_descriptions.data(), - samples_length, secure_fd_array.data()); + const MessageKeyData& key = license_api_fuzz.session()->license().keys[0]; + vector key_handle; + GetKeyHandleIntoVector(session_id, key.key_id, key.key_id_length, + fuzzed_structure.cipher_mode, key_handle); + OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + sample_descriptions.data(), sample_descriptions.size(), + &fuzzed_structure.pattern); + + // Free all output buffers. + FreeOutputBuffers(sample_descriptions.size()); + return 0; } + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc index f76fafa..eb6a351 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc @@ -6,19 +6,18 @@ namespace wvoec { void RedirectStdoutToFile() { freopen("log.txt", "a", stdout); } -std::vector> SplitInput(const uint8_t* data, size_t size) { - std::vector> result; - auto current_pos = data; - auto end = data + size; - // Using memmem to find separator - while (const uint8_t* pos = reinterpret_cast( - memmem(current_pos, end - current_pos, kFuzzDataSeparator, - sizeof(kFuzzDataSeparator)))) { - result.push_back({current_pos, pos}); - current_pos = pos + sizeof(kFuzzDataSeparator); +std::vector SplitFuzzedData(const uint8_t* data, size_t size) { + std::vector result; + const uint8_t* const end = data + size; + // Using memmem to find separator. + while ( + const uint8_t* const separator = reinterpret_cast(memmem( + data, end - data, kFuzzDataSeparator, sizeof(kFuzzDataSeparator)))) { + result.push_back({data, static_cast(separator - data)}); + data = separator + sizeof(kFuzzDataSeparator); } - if (current_pos < end) { - result.push_back({current_pos, end}); + if (data < end) { + result.push_back({data, static_cast(end - data)}); } return result; } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h index 2aa1f46..15b7363 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h @@ -20,9 +20,16 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize) __attribute__((weak)); const size_t KB = 1024; -// Maximum signature length. If fuzzed signature length is greater that this, -// this value will be used for signature length. -const size_t MAX_FUZZ_SIGNATURE_LENGTH = 5 * KB; + +// Default maximum length of fuzzing output parameters. +const size_t MAX_FUZZ_OUTPUT_LENGTH = 5 * KB; + +// Fuzzed data region. +struct FuzzedData { + const uint8_t* data; + size_t size; +}; + // Initial setup to create a valid OEMCrypto state such as initializing crypto // firmware/hardware, installing golden key box etc. in order to fuzz // OEMCrypto APIs. @@ -32,7 +39,8 @@ class InitializeFuzz : public SessionUtil { wvoec::global_features.Initialize(); OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); OEMCrypto_Initialize(); - EnsureTestKeys(); + OEMCrypto_EnterTestMode(); + EnsureTestROT(); } ~InitializeFuzz() { OEMCrypto_Terminate(); } @@ -42,7 +50,7 @@ class OEMCryptoLicenseAPIFuzz : public InitializeFuzz { public: OEMCryptoLicenseAPIFuzz() : license_messages_(&session_) { session_.open(); - InstallTestRSAKey(&session_); + InstallTestDrmKey(&session_); session_.GenerateNonce(); } @@ -52,6 +60,8 @@ class OEMCryptoLicenseAPIFuzz : public InitializeFuzz { Session* session() { return &session_; } + uint32_t session_id() { return session_.session_id(); } + void LoadLicense(); private: @@ -111,20 +121,27 @@ class LicenseWithUsageEntryFuzz : public InitializeFuzz { Session session_; }; -// Convert data to valid enum value. +// Convert data from FuzzedDataProvider to valid enum value. +template +T ConvertDataToValidEnum(FuzzedDataProvider& fuzzed_data, T max_enum_value) { + return static_cast(fuzzed_data.ConsumeIntegralInRange( + 0, static_cast(max_enum_value))); +} + +// Convert data to valid enum value in place. template void ConvertDataToValidEnum(T max_enum_value, T* t) { FuzzedDataProvider fuzzed_enum_data(reinterpret_cast(t), sizeof(T)); - *t = static_cast(fuzzed_enum_data.ConsumeIntegralInRange( - 0, static_cast(max_enum_value))); + *t = ConvertDataToValidEnum(fuzzed_enum_data, max_enum_value); } // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise void RedirectStdoutToFile(); -// Function to split fuzzer input using delimiter "-_^_". -std::vector> SplitInput(const uint8_t* data, size_t size); +// Split fuzzed data using delimiter "-_^_". +std::vector SplitFuzzedData(const uint8_t* data, size_t size); + // Check the status and exit fuzzer if arguments do not match. This is usually // called to check status of APIs which are called to setup state for fuzzers. void CheckStatusAndExitFuzzerOnFailure(OEMCryptoResult result, diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h index 37b3daf..42d077c 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h @@ -8,6 +8,26 @@ #include "odk.h" namespace wvoec { + +// OEMCrypto_DestBufferDesc fuzzed properties. +struct OEMCrypto_DestBufferDesc_Fuzz { + OEMCryptoBufferType type; + size_t buffer_config; +}; + +// OEMCrypto_InputOutputPair fuzzed properties. +struct OEMCrypto_InputOutputPair_Fuzz { + size_t input_data_length; + OEMCrypto_DestBufferDesc_Fuzz output_descriptor; +}; + +// OEMCrypto_SampleDescription fuzzed properties. +struct OEMCrypto_SampleDescription_Fuzz { + OEMCrypto_InputOutputPair_Fuzz buffers; + uint8_t iv[16]; + size_t subsamples_length; +}; + struct OEMCrypto_Renewal_Response_Fuzz { // Timer limits in core license response needs to be fuzzed as load renewal // depends on timer limits loaded from license response. @@ -50,16 +70,6 @@ struct OEMCrypto_Generic_Api_Fuzz { // this structure. }; -struct OEMCrypto_Generic_Verify_Fuzz { - // Corpus format is as belowr. - // cipher_mode + algorithm + signature_length + buffer with actual data - OEMCryptoCipherMode cipher_mode; - OEMCrypto_Algorithm algorithm; - size_t signature_length; - // Buffer data is of variable length and not included in - // this structure. -}; - struct OEMCrypto_Generate_RSA_Signature_Fuzz { // Corpus format is as below, let | be separator. // padding_scheme + signature_length + input buffer @@ -72,10 +82,11 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz { struct OEMCrypto_Copy_Buffer_Fuzz { // Corpus format is as below. // dest_buffer_desc + subsample_flags + input buffer - OEMCrypto_DestBufferDesc dest_buffer_desc; + OEMCrypto_DestBufferDesc_Fuzz dest_buffer_desc; uint8_t subsample_flags; // Input buffer of variable length is not included in this structure. }; + } // namespace wvoec -#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ \ No newline at end of file +#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp deleted file mode 100644 index 458e3b8..0000000 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -#source code may only be used and distributed under the Widevine License -#Agreement. -# -# Builds under the CDM ./build.py (target platform) build system -# Refer to the distribution package's README for details. -{ - 'target_defaults': { - 'type': 'executable', - 'includes': [ - 'oemcrypto_fuzztests.gypi', - ], - }, - 'variables': { - # Flag to select appropriate underlying oemcrypto implementation when - # buiding fuzz binaries. - 'oemcrypto_implementation_version%': 'reference', - }, - 'targets': [ - { - 'target_name': 'oemcrypto_load_license_fuzz', - 'sources': [ - 'oemcrypto_load_license_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_encrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_encrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_decrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_decrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_sign_fuzz', - 'sources': [ - 'oemcrypto_generic_sign_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_verify_fuzz', - 'sources': [ - 'oemcrypto_generic_verify_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generate_rsa_signature_fuzz', - 'sources': [ - 'oemcrypto_generate_rsa_signature_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_table_header_fuzz', - 'sources': [ - 'oemcrypto_load_usage_table_header_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_load_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_deactivate_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_deactivate_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_report_usage_fuzz', - 'sources': [ - 'oemcrypto_report_usage_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_copy_buffer_fuzz', - 'sources': [ - 'oemcrypto_copy_buffer_fuzz.cc', - ], - }, - ], -} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi index cdbeadd..f8abdec 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi @@ -29,6 +29,7 @@ '<(util_dir)/src/platform.cpp', '<(util_dir)/src/rw_lock.cpp', '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', '<(util_dir)/test/test_sleep.cpp', '<(util_dir)/test/test_clock.cpp', ], @@ -102,18 +103,11 @@ '-fcoverage-mapping', ], }], - ['oemcrypto_implementation_version=="reference"', { - # Include oemcrypto reference implementation code for building reference - # implementation fuzz binaries. - 'includes': [ - '../../ref/oec_ref.gypi', - ], - }], ['oemcrypto_implementation_version=="opk"', { # Include oemcrypto opk implementation code for building opk # implementation fuzz binaries. 'dependencies': [ - '<(oemcrypto_dir)/opk/ports/linux/wtpi_test_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', + '<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', ], }], ], # conditions diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc index 872b302..39aa72c 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc @@ -2,6 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" @@ -11,23 +12,25 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise RedirectStdoutToFile(); + OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; - if (size <= sizeof(OEMCrypto_Generate_RSA_Signature_Fuzz)) { + if (size < sizeof(fuzzed_structure)) { return 0; } + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + const std::vector message = + fuzzed_data.ConsumeRemainingBytes(); - // Copy data to fuzzed structure. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); // Creates wrapped rsa key and calls load drm private key. static OEMCryptoLicenseAPIFuzz license_api_fuzz; // We cannot allocate buffers of random huge lengths in memory. // This also slows down the fuzzer. - size_t signature_length = - std::min(MAX_FUZZ_SIGNATURE_LENGTH, fuzzed_structure.signature_length); - vector signature(signature_length); + fuzzed_structure.signature_length %= MAX_FUZZ_OUTPUT_LENGTH + 1; + std::vector signature(fuzzed_structure.signature_length); OEMCrypto_GenerateRSASignature( - license_api_fuzz.session()->session_id(), data + sizeof(fuzzed_structure), - size - sizeof(fuzzed_structure), signature.data(), &signature_length, + license_api_fuzz.session()->session_id(), message.data(), message.size(), + signature.data(), &fuzzed_structure.signature_length, fuzzed_structure.padding_scheme); return 0; } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc index 19b60b7..6531457 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc @@ -15,7 +15,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { } OEMCrypto_Initialize(); - session_helper.EnsureTestKeys(); + OEMCrypto_EnterTestMode(); + session_helper.EnsureTestROT(); Session s; s.open(); diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc index e36d550..1bf5570 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc @@ -5,6 +5,7 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" +#include "oec_session_util.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" #include "oemcrypto_types.h" @@ -16,46 +17,43 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { RedirectStdoutToFile(); // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + const std::vector iv = fuzzed_data.ConsumeRemainingBytes(); - // Copy clear buffer from input data. - vector encrypted_buffer(inputs[1].size()); - vector clear_buffer(inputs[1].size()); - memcpy(encrypted_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize encrypted and clear buffers. + const std::vector encrypted_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector clear_buffer(encrypted_buffer.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); // Load license and call generic_decrypt API. license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); - OEMCrypto_Generic_Decrypt(session->session_id(), encrypted_buffer.data(), - encrypted_buffer.size(), iv.data(), - fuzzed_structure.algorithm, clear_buffer.data()); + vector key_handle; + GetKeyHandleIntoVector(session->session_id(), + session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_structure.cipher_mode, key_handle); + OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(), + encrypted_buffer.data(), encrypted_buffer.size(), + iv.data(), fuzzed_structure.algorithm, + clear_buffer.data()); return 0; } } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc index df0a35e..0c9c8fa 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc @@ -5,6 +5,7 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" +#include "oec_session_util.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" #include "oemcrypto_types.h" @@ -16,46 +17,43 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { RedirectStdoutToFile(); // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + const std::vector iv = fuzzed_data.ConsumeRemainingBytes(); - // Copy clear buffer from input data. - vector clear_buffer(inputs[1].size()); - vector encrypted_buffer(inputs[1].size()); - memcpy(clear_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize clear and encrypted buffers. + const std::vector clear_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector encrypted_buffer(clear_buffer.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); // Load license and call generic_encrypt API. license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); - OEMCrypto_Generic_Encrypt( - session->session_id(), clear_buffer.data(), clear_buffer.size(), - iv.data(), fuzzed_structure.algorithm, encrypted_buffer.data()); + vector key_handle; + GetKeyHandleIntoVector(session->session_id(), + session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_structure.cipher_mode, key_handle); + OEMCrypto_Generic_Encrypt(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), iv.data(), + fuzzed_structure.algorithm, + encrypted_buffer.data()); return 0; } } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc index d27415d..103668e 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc @@ -2,8 +2,10 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" +#include "oec_session_util.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" #include "oemcrypto_types.h" @@ -19,37 +21,35 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - - size_t clear_buffer_size = size - sizeof(fuzzed_structure); - if (clear_buffer_size == 0) { - return 0; - } // Copy clear buffer from input data. - vector clear_buffer(clear_buffer_size); - memcpy(clear_buffer.data(), data + sizeof(fuzzed_structure), - clear_buffer_size); + const std::vector clear_buffer = + fuzzed_data.ConsumeRemainingBytes(); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); // Load license and call generic_sign API. license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); + vector key_handle; + GetKeyHandleIntoVector(session->session_id(), + session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_structure.cipher_mode, key_handle); size_t signature_length = 0; - OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), - clear_buffer.size(), fuzzed_structure.algorithm, - nullptr, &signature_length); - vector signature(signature_length); - OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), - clear_buffer.size(), fuzzed_structure.algorithm, - signature.data(), &signature_length); + OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), + fuzzed_structure.algorithm, nullptr, + &signature_length); + std::vector signature(signature_length); + OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), + fuzzed_structure.algorithm, signature.data(), + &signature_length); return 0; } } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc index 759286d..23f598d 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc @@ -2,66 +2,135 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include -#include - +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" +#include "oec_session_util.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" #include "oemcrypto_types.h" namespace wvoec { -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; - if (size < sizeof(fuzzed_structure)) { - return 0; +// Properties deserialized from fuzzed data. +struct FuzzedProperties { + OEMCrypto_Generic_Api_Fuzz structure; + std::vector buffer; + std::vector signature; +}; + +// Contains value only if has_value is true. +struct OptionalFuzzedProperties { + FuzzedProperties value; + bool has_value; +}; + +OEMCryptoLicenseAPIFuzz license_api_fuzz; + +OptionalFuzzedProperties DeserializeFuzzedData(const uint8_t* data, + size_t size) { + OptionalFuzzedProperties fuzzed_properties; + const std::vector inputs = SplitFuzzedData(data, size); + if (inputs.size() < 2 || + inputs[0].size < sizeof(fuzzed_properties.value.structure)) { + fuzzed_properties.has_value = false; + return fuzzed_properties; } - // Copy OEMCrypto_Generic_Verify_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_properties.value.structure, + sizeof(fuzzed_properties.value.structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); + &fuzzed_properties.value.structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); + &fuzzed_properties.value.structure.algorithm); + fuzzed_properties.value.buffer = fuzzed_data.ConsumeRemainingBytes(); + fuzzed_properties.value.signature.assign(inputs[1].data, + inputs[1].data + inputs[1].size); + fuzzed_properties.has_value = true; + return fuzzed_properties; +} - size_t in_buffer_size = size - sizeof(fuzzed_structure); - if (in_buffer_size == 0) { - return 0; - } - // Copy clear buffer from input data. - vector in_buffer(in_buffer_size); - memcpy(in_buffer.data(), data + sizeof(fuzzed_structure), in_buffer_size); - - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_verify API. +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + RedirectStdoutToFile(); license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - OEMCrypto_CipherMode_CENC); - // Calculate signature for in buffer. - size_t signature_length = 0; - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, nullptr, - &signature_length); - vector signature(signature_length); - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), &signature_length); - - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - fuzzed_structure.cipher_mode); - signature_length = - std::min(MAX_FUZZ_SIGNATURE_LENGTH, fuzzed_structure.signature_length); - signature.resize(signature_length); - OEMCrypto_Generic_Verify(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), signature_length); return 0; } + +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, + size_t max_size, unsigned int seed) { + // Deserialize fuzzed data. + OptionalFuzzedProperties fuzzed_properties = + DeserializeFuzzedData(data, size); + if (!fuzzed_properties.has_value) { + return 0; + } + + // Get key handle for signing and verifying. + Session* const session = license_api_fuzz.session(); + vector key_handle; + OEMCryptoResult result = GetKeyHandleIntoVector( + session->session_id(), session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_properties.value.structure.cipher_mode, key_handle); + if (result == OEMCrypto_SUCCESS) { + // Generate a new signature if verification fails. + result = + OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), + fuzzed_properties.value.signature.size()); + if (result != OEMCrypto_SUCCESS) { + size_t signature_length = 0; + OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + nullptr, &signature_length); + fuzzed_properties.value.signature.resize(signature_length); + OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), + &signature_length); + const size_t signature_offset = + sizeof(fuzzed_properties.value.structure) + + fuzzed_properties.value.buffer.size() + sizeof(kFuzzDataSeparator); + size = signature_offset + signature_length; + if (size > max_size) { + return 0; + } + memcpy(data + signature_offset, fuzzed_properties.value.signature.data(), + signature_length); + } + } + + return LLVMFuzzerMutate(data, size, max_size); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Deserialize fuzzed data. + const OptionalFuzzedProperties fuzzed_properties = + DeserializeFuzzedData(data, size); + if (!fuzzed_properties.has_value) { + return 0; + } + + // Select key and perform verification. + Session* const session = license_api_fuzz.session(); + vector key_handle; + GetKeyHandleIntoVector( + session->session_id(), session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_properties.value.structure.cipher_mode, key_handle); + OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), + fuzzed_properties.value.signature.size()); + return 0; +} + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_install_oem_private_key_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_install_oem_private_key_fuzz.cc new file mode 100644 index 0000000..dcd3c05 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_install_oem_private_key_fuzz.cc @@ -0,0 +1,41 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "FuzzedDataProvider.h" +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" + +namespace wvoec { +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + + if (size < sizeof(OEMCrypto_PrivateKeyType)) { + return 0; + } + + LicenseWithUsageEntryFuzz entry; + entry.CreateUsageTableHeader(); + // Open a session, create a usage entry. + Session* session = entry.license_messages().session(); + session->open(); + entry.InstallTestDrmKey(session); + session->GenerateNonce(); + session->CreateNewUsageEntry(); + std::vector encrypted_usage_header; + session->UpdateUsageEntry(&encrypted_usage_header); + FuzzedDataProvider fuzzed_data(data, size); + const OEMCrypto_PrivateKeyType key_type = + ConvertDataToValidEnum(fuzzed_data, OEMCrypto_PrivateKeyType_MaxValue); + const std::vector wrapped_private_key = + fuzzed_data.ConsumeRemainingBytes(); + OEMCrypto_InstallOemPrivateKey(session->session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key.size()); + session->close(); + + return 0; +} +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc index fbb33e6..fcc53a0 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc @@ -2,9 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" -#include "oemcrypto_fuzz_structs.h" namespace wvoec { @@ -17,34 +15,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // message buffer with key data | entitled content key object array with // offsets and lengths to read key data from message buffer. // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } - FuzzedDataProvider fuzzed_entitled_content_key_array(inputs[1].data(), - inputs[1].size()); - - // Message to be verified. Return 0 if key data buffer is empty. - if (inputs[0].size() == 0) { - return 0; - } - // Copy data to OEMCrypto_EntitledContentKeyObject array. - size_t entitled_content_key_object_size = - sizeof(OEMCrypto_EntitledContentKeyObject); - size_t entitled_content_key_array_length = - fuzzed_entitled_content_key_array.remaining_bytes() / - entitled_content_key_object_size; - if (entitled_content_key_array_length == 0) { - return 0; - } - OEMCrypto_EntitledContentKeyObject* entitled_content_key_array = - new OEMCrypto_EntitledContentKeyObject[entitled_content_key_array_length]; - - for (size_t i = 0; i < entitled_content_key_array_length; i++) { - fuzzed_entitled_content_key_array.ConsumeData( - &entitled_content_key_array[i], entitled_content_key_object_size); + std::vector entitled_content_keys( + inputs[1].size / sizeof(OEMCrypto_EntitledContentKeyObject)); + if (!entitled_content_keys.empty()) { + memcpy(entitled_content_keys.data(), inputs[1].data, + entitled_content_keys.size() * + sizeof(OEMCrypto_EntitledContentKeyObject)); } OEMCryptoLicenseAPIFuzz license_api_fuzz; @@ -54,13 +36,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { OEMCrypto_EntitlementLicense); license_api_fuzz.LoadLicense(); // Call OEMCrypto_LoadEntitledContentKeys with fuzzed buffers. - Session* session = license_api_fuzz.session(); - uint8_t* fuzzed_key_data = inputs[0].data(); - size_t fuzzed_key_data_size = inputs[0].size(); + const std::vector message(inputs[0].data, + inputs[0].data + inputs[0].size); OEMCrypto_LoadEntitledContentKeys( - session->session_id(), fuzzed_key_data, fuzzed_key_data_size, - entitled_content_key_array_length, entitled_content_key_array); - delete[] entitled_content_key_array; + license_api_fuzz.session()->session_id(), message.data(), message.size(), + entitled_content_keys.size(), entitled_content_keys.data()); return 0; } + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc index ed47b0b..17c5150 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc @@ -2,33 +2,50 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" namespace wvoec { -LicenseWithUsageEntryFuzz entry; + +OEMCryptoResult LoadUsageEntryWithFuzzedData(OEMCrypto_SESSION session, + const uint8_t* data, size_t size) { + if (size < sizeof(uint32_t)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + FuzzedDataProvider fuzzed_data(data, size); + const uint32_t usage_entry_number = fuzzed_data.ConsumeIntegral(); + const std::vector buffer = + fuzzed_data.ConsumeRemainingBytes(); + return OEMCrypto_LoadUsageEntry(session, usage_entry_number, buffer.data(), + buffer.size()); +} + // The custom mutator to mutate created encrypted usage entry. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed) { + LicenseWithUsageEntryFuzz entry; entry.CreateUsageTableHeader(); Session* s = entry.license_messages().session(); s->open(); - entry.InstallTestRSAKey(s); - uint32_t usage_entry_number = 0; - memcpy(&usage_entry_number, data, sizeof(uint32_t)); - if (OEMCrypto_LoadUsageEntry(s->session_id(), usage_entry_number, - data + sizeof(uint32_t), - size - sizeof(uint32_t)) != OEMCrypto_SUCCESS) { + entry.InstallTestDrmKey(s); + if (LoadUsageEntryWithFuzzedData(s->session_id(), data, size) != + OEMCrypto_SUCCESS) { s->CreateNewUsageEntry(); - vector encrypted_usage_header; + std::vector encrypted_usage_header; s->UpdateUsageEntry(&encrypted_usage_header); - vector encrypted_usage_entry = s->encrypted_usage_entry(); - usage_entry_number = s->usage_entry_number(); + const uint32_t usage_entry_number = s->usage_entry_number(); + const std::vector& encrypted_usage_entry = + s->encrypted_usage_entry(); + size = sizeof(usage_entry_number) + encrypted_usage_entry.size(); + if (size > max_size) { + return 0; + } // Copy created usage entry number and usage entry to data and mutate it. - memcpy(data, &usage_entry_number, sizeof(uint32_t)); - memcpy(data + sizeof(uint32_t), encrypted_usage_entry.data(), + memcpy(data, &usage_entry_number, sizeof(usage_entry_number)); + memcpy(data + sizeof(usage_entry_number), encrypted_usage_entry.data(), encrypted_usage_entry.size()); - size = sizeof(uint32_t) + encrypted_usage_entry.size(); } s->close(); return LLVMFuzzerMutate(data, size, max_size); @@ -39,23 +56,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // reduce noise RedirectStdoutToFile(); - uint32_t usage_entry_number = 0; - if (size < sizeof(usage_entry_number)) { - return 0; - } - - memcpy(&usage_entry_number, data, sizeof(usage_entry_number)); - const uint8_t* extra_data = data + sizeof(usage_entry_number); - size_t extra_data_size = size - sizeof(usage_entry_number); - if (extra_data_size == 0) { - return 0; - } - Session s; s.open(); - OEMCrypto_LoadUsageEntry(s.session_id(), usage_entry_number, extra_data, - extra_data_size); + LoadUsageEntryWithFuzzedData(s.session_id(), data, size); s.close(); return 0; } + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc index 8d3000a..19c699a 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc @@ -13,13 +13,13 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, LicenseWithUsageEntryFuzz entry; if (OEMCrypto_LoadUsageTableHeader(data, size) != OEMCrypto_SUCCESS) { entry.CreateUsageTableHeader(); - if (size < entry.encrypted_usage_header().size()) { + size = entry.encrypted_usage_header().size(); + if (size > max_size) { return 0; } // Copy created usage table header to data and mutate it. memcpy(data, entry.encrypted_usage_header().data(), entry.encrypted_usage_header().size()); - size = entry.encrypted_usage_header().size(); } return LLVMFuzzerMutate(data, size, max_size); } @@ -33,4 +33,5 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { OEMCrypto_LoadUsageTableHeader(data, size); return 0; } + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_move_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_move_usage_entry_fuzz.cc new file mode 100644 index 0000000..10c2d30 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_move_usage_entry_fuzz.cc @@ -0,0 +1,33 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" + +namespace wvoec { +LicenseWithUsageEntryFuzz entry; +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + + uint32_t usage_entry_number = 0; + if (size < sizeof(usage_entry_number)) { + return 0; + } + + entry.CreateUsageTableHeader(); + Session* s = entry.license_messages().session(); + s->open(); + entry.InstallTestDrmKey(s); + memcpy(&usage_entry_number, data, sizeof(uint32_t)); + s->CreateNewUsageEntry(); + vector encrypted_usage_header; + s->UpdateUsageEntry(&encrypted_usage_header); + OEMCrypto_MoveEntry(s->session_id(), usage_entry_number); + s ->close(); + + return 0; +} +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc index 3fae8e6..537e90e 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc @@ -1,40 +1,38 @@ -#include -#include +#include #include "opk_dispatcher.h" #include "opk_init.h" -#include "tos_transport_interface.h" namespace wvoec { void OpenOEMCryptoTASession() { - ODK_Message request; - ODK_Message response; - uint8_t response_buffer[0x1000]; uint8_t request_body[] = { - 0x06, // TAG_UINT32 - 0x09, 0x00, 0x00, 0x00, // API value (0x09) - 0x01, // TAG_BOOL - 0x00, // value (false) - 0x0a // TAG_EOM + 0x06, // TAG_UINT32 + 0x09, 0x00, 0x00, 0x00, // API value (0x09) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x01, // TAG_BOOL + 0x00, // value (false) + 0x0a // TAG_EOM }; - request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; OPK_DispatchMessage(&request, &response); } void InitializeOEMCryptoTA() { - ODK_Message init_request; - ODK_Message init_response; - uint8_t response_buffer[0x1000]; - uint8_t init_request_body[] = { - 0x06, // TAG_UINT32 - 0x01, 0x00, 0x00, 0x00, // API value(0x01) - 0x0a // TAG_EOM + uint8_t request_body[] = { + 0x06, // TAG_UINT32 + 0x01, 0x00, 0x00, 0x00, // API value (0x01) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x0a // TAG_EOM }; - - init_request = - ODK_Message_Create(init_request_body, sizeof(init_request_body)); - OPK_DispatchMessage(&init_request, &init_response); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; + OPK_DispatchMessage(&request, &response); } extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { @@ -45,17 +43,12 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - ODK_Message request; + std::vector request_body(data, data + size); + ODK_Message request = + ODK_Message_Create(request_body.data(), request_body.size()); + ODK_Message_SetSize(&request, request_body.size()); ODK_Message response; - unsigned char response_buffer[0x1000]; - - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - - request = ODK_Message_Create(input, size); OPK_DispatchMessage(&request, &response); - - delete[] input; return 0; } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi index 0a655fc..5c99ee4 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi @@ -47,6 +47,12 @@ ], 'defines': [ 'OPK_LOG_LEVEL=LOG_NONE', + 'OPK_CONFIG_SOC_VENDOR_NAME=test', + 'OPK_CONFIG_SOC_MODEL_NAME=test', + 'OPK_CONFIG_TEE_OS_NAME=TEE_Simulator', + 'OPK_CONFIG_TEE_OS_VERSION=0.0.0', + 'OPK_CONFIG_DEVICE_FORM_FACTOR=oemcrypto_opk_fuzztests', + 'OPK_CONFIG_IMPLEMENTER_NAME=Widevine', ], 'conditions': [ ['generate_code_coverage_report=="true"', { diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc index 3b3813a..d4df351 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc @@ -2,6 +2,7 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" namespace wvoec { @@ -11,8 +12,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // reduce noise RedirectStdoutToFile(); - size_t pst_buffer_length = 0; - if (size <= sizeof(pst_buffer_length)) { + if (size < sizeof(size_t)) { return 0; } @@ -21,25 +21,22 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Open a session, create a usage entry. Session* session = entry.license_messages().session(); session->open(); - entry.InstallTestRSAKey(session); - session->GenerateNonce(); + entry.InstallTestDrmKey(session); session->CreateNewUsageEntry(); + session->GenerateNonce(); vector encrypted_usage_header; session->UpdateUsageEntry(&encrypted_usage_header); // Sets pst for usage entry. entry.LoadLicense(); - memcpy(&pst_buffer_length, data, sizeof(pst_buffer_length)); - const uint8_t* extra_data = data + sizeof(pst_buffer_length); - size_t extra_data_size = size - sizeof(pst_buffer_length); - // We cannot allocate a huge buffer, hence limiting buffer size to - // MAX_FUZZ_PST_REPORT_BUFFER_LENGTH. - pst_buffer_length = - std::min(MAX_FUZZ_PST_REPORT_BUFFER_LENGTH, pst_buffer_length); - vector pst_report_buffer(pst_buffer_length); + FuzzedDataProvider fuzzed_data(data, size); + size_t pst_report_buffer_length = fuzzed_data.ConsumeIntegralInRange( + 0, MAX_FUZZ_PST_REPORT_BUFFER_LENGTH); + const std::vector pst = fuzzed_data.ConsumeRemainingBytes(); + std::vector pst_report_buffer(pst_report_buffer_length); // Call API with fuzzed pst_buffer_length, pst. - OEMCrypto_ReportUsage(session->session_id(), extra_data, extra_data_size, - pst_report_buffer.data(), &pst_buffer_length); + OEMCrypto_ReportUsage(session->session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), &pst_report_buffer_length); session->close(); return 0; } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_reuse_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_reuse_usage_entry_fuzz.cc new file mode 100644 index 0000000..c825498 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_reuse_usage_entry_fuzz.cc @@ -0,0 +1,33 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" + +namespace wvoec { +LicenseWithUsageEntryFuzz entry; +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + + uint32_t usage_entry_number = 0; + if (size < sizeof(usage_entry_number)) { + return 0; + } + + entry.CreateUsageTableHeader(); + Session* s = entry.license_messages().session(); + s->open(); + entry.InstallTestDrmKey(s); + s->CreateNewUsageEntry(); + s->close(); + s->open(); + memcpy(&usage_entry_number, data, sizeof(uint32_t)); + OEMCrypto_ReuseUsageEntry(s->session_id(), usage_entry_number); + s->close(); + + return 0; +} +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_shrink_usage_table_header_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_shrink_usage_table_header_fuzz.cc new file mode 100644 index 0000000..625b0f0 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_shrink_usage_table_header_fuzz.cc @@ -0,0 +1,31 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "FuzzedDataProvider.h" +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" + +namespace wvoec { +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + + if (size < sizeof(uint32_t) + sizeof(size_t)) { + return 0; + } + + LicenseWithUsageEntryFuzz entry; + entry.CreateUsageTableHeader(); + FuzzedDataProvider fuzzed_data(data, size); + const uint32_t new_entry_count = fuzzed_data.ConsumeIntegral(); + size_t header_buffer_length = + fuzzed_data.ConsumeIntegralInRange(0, MAX_FUZZ_OUTPUT_LENGTH); + std::vector header_buffer(header_buffer_length); + OEMCrypto_ShrinkUsageTableHeader(new_entry_count, header_buffer.data(), + &header_buffer_length); + + return 0; +} +} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi index 18eb2ad..ddf927d 100644 --- a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi @@ -27,6 +27,7 @@ '<(util_dir)/src/platform.cpp', '<(util_dir)/src/rw_lock.cpp', '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', '<(util_dir)/test/test_sleep.cpp', '<(util_dir)/test/test_clock.cpp', ], diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index 8eebf9b..6cb7aac 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -49,11 +49,12 @@ namespace wvoec { // Decrypts the given array of samples. Handles fallback behavior correctly if // the OEMCrypto implementation does not accept multiple samples. OEMCryptoResult DecryptFallbackChain::Decrypt( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples, - size_t samples_length, OEMCryptoCipherMode cipher_mode, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + OEMCryptoCipherMode cipher_mode, const OEMCrypto_CENCEncryptPatternDesc* pattern) { - OEMCryptoResult sts = - OEMCrypto_DecryptCENC(session_id, samples, samples_length, pattern); + OEMCryptoResult sts = OEMCrypto_DecryptCENC(key_handle, key_handle_length, + samples, samples_length, pattern); // No need for a fallback. Abort early. if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) { @@ -65,7 +66,8 @@ OEMCryptoResult DecryptFallbackChain::Decrypt( // Fall back to decrypting individual samples. for (size_t i = 0; i < samples_length; ++i) { - sts = DecryptSample(session_id, samples[i], cipher_mode, pattern); + sts = DecryptSample(key_handle, key_handle_length, samples[i], cipher_mode, + pattern); if (sts != OEMCrypto_SUCCESS) return sts; } @@ -75,10 +77,11 @@ OEMCryptoResult DecryptFallbackChain::Decrypt( // Decrypts the given sample. Handles fallback behavior correctly if the // OEMCrypto implementation does not accept full samples. OEMCryptoResult DecryptFallbackChain::DecryptSample( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, - OEMCryptoCipherMode cipher_mode, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, OEMCryptoCipherMode cipher_mode, const OEMCrypto_CENCEncryptPatternDesc* pattern) { - OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern); + OEMCryptoResult sts = + OEMCrypto_DecryptCENC(key_handle, key_handle_length, &sample, 1, pattern); // No need for a fallback. Abort early. if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) { @@ -99,7 +102,8 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( fake_sample.subsamples = &subsample; fake_sample.subsamples_length = 1; - sts = DecryptSubsample(session_id, fake_sample, pattern, cipher_mode); + sts = DecryptSubsample(key_handle, key_handle_length, fake_sample, pattern, + cipher_mode); if (sts != OEMCrypto_SUCCESS) return sts; fake_sample.buffers.input_data += length; @@ -116,10 +120,12 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( // Decrypts the given subsample. Handles fallback behavior correctly if the // OEMCrypto implementation does not accept full subsamples. OEMCryptoResult DecryptFallbackChain::DecryptSubsample( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, const OEMCrypto_CENCEncryptPatternDesc* pattern, OEMCryptoCipherMode cipher_mode) { - OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern); + OEMCryptoResult sts = + OEMCrypto_DecryptCENC(key_handle, key_handle_length, &sample, 1, pattern); // No need for a fallback. Abort early. if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) { @@ -149,7 +155,8 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( subsample.num_bytes_encrypted == 0) fake_subsample.subsample_flags |= OEMCrypto_LastSubsample; - sts = DecryptSubsampleHalf(session_id, fake_sample, pattern, cipher_mode); + sts = DecryptSubsampleHalf(key_handle, key_handle_length, fake_sample, + pattern, cipher_mode); if (sts != OEMCrypto_SUCCESS) return sts; // Advance the buffers for the other half, in case they're needed. @@ -171,7 +178,8 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.subsample_flags & OEMCrypto_LastSubsample) fake_subsample.subsample_flags |= OEMCrypto_LastSubsample; - sts = DecryptSubsampleHalf(session_id, fake_sample, pattern, cipher_mode); + sts = DecryptSubsampleHalf(key_handle, key_handle_length, fake_sample, + pattern, cipher_mode); if (sts != OEMCrypto_SUCCESS) return sts; } @@ -182,13 +190,15 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( // an OEMCrypto_ERROR_BUFFER_TOO_LARGE produced here will be returned to the // caller. OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, const OEMCrypto_CENCEncryptPatternDesc* pattern, OEMCryptoCipherMode cipher_mode) { if (ShouldGenerateCorpus()) { WriteDecryptCencCorpus(cipher_mode, &sample, pattern, 1); } - return OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern); + return OEMCrypto_DecryptCENC(key_handle, key_handle_length, &sample, 1, + pattern); // In a real CDM, you would want some fallback here to handle the case where // the buffer is too big for the OEMCrypto implementation. But in the case of // the tests, we won't be passing a buffer that's too big unless we are trying @@ -198,26 +208,64 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf( // Used for OEMCrypto Fuzzing: Corpus format is as below, let | be separator. // cipher_mode + pattern + sample_data for all samples | -// subsample_data for all samples +// input_data for all samples | subsample_data for all samples void WriteDecryptCencCorpus( OEMCryptoCipherMode cipher_mode, const OEMCrypto_SampleDescription* samples_description, const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) { const std::string file_name = GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus"); + + // Cipher mode and Pattern. OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct; decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode; decrypt_cenc_fuzz_struct.pattern = *pattern; - // Cipher mode and Pattern. AppendToFile(file_name, reinterpret_cast(&decrypt_cenc_fuzz_struct), sizeof(OEMCrypto_Decrypt_Cenc_Fuzz)); // Sample data for all samples. for (size_t i = 0; i < samples_length; i++) { + OEMCrypto_SampleDescription_Fuzz sample_description_data; + sample_description_data.buffers.input_data_length = + samples_description[i].buffers.input_data_length; + sample_description_data.buffers.output_descriptor.type = + samples_description[i].buffers.output_descriptor.type; + switch (sample_description_data.buffers.output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.direct.is_video; + break; + } + memcpy(sample_description_data.iv, samples_description[i].iv, + sizeof(sample_description_data.iv)); + sample_description_data.subsamples_length = + samples_description[i].subsamples_length; AppendToFile(file_name, - reinterpret_cast(&samples_description[i]), - sizeof(OEMCrypto_SampleDescription)); + reinterpret_cast(&sample_description_data), + sizeof(OEMCrypto_SampleDescription_Fuzz)); + } + AppendSeparator(file_name); + + // Input data for all samples. + for (size_t i = 0; i < samples_length; i++) { + AppendToFile(file_name, + reinterpret_cast( + samples_description[i].buffers.input_data), + samples_description[i].buffers.input_data_length); } AppendSeparator(file_name); diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.h b/oemcrypto/test/oec_decrypt_fallback_chain.h index aafbb07..0bbee74 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.h +++ b/oemcrypto/test/oec_decrypt_fallback_chain.h @@ -32,23 +32,27 @@ namespace wvoec { class DecryptFallbackChain { public: static OEMCryptoResult Decrypt( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples, - size_t samples_length, OEMCryptoCipherMode cipher_mode, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription* samples, size_t samples_length, + OEMCryptoCipherMode cipher_mode, const OEMCrypto_CENCEncryptPatternDesc* pattern); private: static OEMCryptoResult DecryptSample( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, OEMCryptoCipherMode cipher_mode, const OEMCrypto_CENCEncryptPatternDesc* pattern); static OEMCryptoResult DecryptSubsample( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, const OEMCrypto_CENCEncryptPatternDesc* pattern, OEMCryptoCipherMode cipher_mode); static OEMCryptoResult DecryptSubsampleHalf( - OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample, + const uint8_t* key_handle, size_t key_handle_length, + const OEMCrypto_SampleDescription& sample, const OEMCrypto_CENCEncryptPatternDesc* pattern, OEMCryptoCipherMode cipher_mode); diff --git a/oemcrypto/test/oec_device_features.cpp b/oemcrypto/test/oec_device_features.cpp index 9db9c00..9c91f5a 100644 --- a/oemcrypto/test/oec_device_features.cpp +++ b/oemcrypto/test/oec_device_features.cpp @@ -24,13 +24,27 @@ void DeviceFeatures::Initialize() { generic_crypto = false; usage_table = false; supports_rsa_3072 = false; + supports_secp256r1 = false; api_version = 0; derive_key_method = NO_METHOD; OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); - if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { - printf("OEMCrypto_Initialize failed. All tests will fail.\n"); + const OEMCryptoResult init_status = OEMCrypto_Initialize(); + if (OEMCrypto_SUCCESS != init_status) { + printf("OEMCrypto_Initialize failed %d. All tests will fail.\n", + init_status); return; } + const OEMCryptoResult api_status = OEMCrypto_SetMaxAPIVersion(kCurrentAPI); + if (api_status != OEMCrypto_SUCCESS && + api_status != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + // Log error, but continue assuming no error. + printf("OEMCrypto_SetMaxAPIVersion returned %d\n", api_status); + } + const OEMCryptoResult test_mode_status = OEMCrypto_EnterTestMode(); + if (OEMCrypto_SUCCESS != test_mode_status) { + printf("OEMCrypto_EnterTestMode returned %d. Tests might fail.\n", + test_mode_status); + }; uint8_t buffer[1]; uint8_t iv[16] = {}; size_t size = 0; @@ -60,7 +74,7 @@ void DeviceFeatures::Initialize() { printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false"); generic_crypto = (OEMCrypto_ERROR_NOT_IMPLEMENTED != - OEMCrypto_Generic_Encrypt(session, buffer, 0, iv, + OEMCrypto_Generic_Encrypt(buffer, 0, buffer, 0, iv, OEMCrypto_AES_CBC_128_NO_PADDING, buffer)); printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false"); supports_cas = @@ -70,21 +84,28 @@ void DeviceFeatures::Initialize() { OEMCrypto_CloseSession(session); api_version = OEMCrypto_APIVersion(); printf("api_version = %u.\n", api_version); + if (api_version < kCoreMessagesAPI) { + printf("--------- WARNING: minimum API is %d ----------\n", api_version); + printf("--------- Expect most tests will fail. --------\n"); + } // These unit tests only work with new usage tables. We do not test v12 // usage tables. - if (api_version > 12) usage_table = OEMCrypto_SupportsUsageTable(); + usage_table = OEMCrypto_SupportsUsageTable(); printf("usage_table = %s.\n", usage_table ? "true" : "false"); PickDerivedKey(); - if (api_version >= 13) { - uint32_t supported_cert = OEMCrypto_SupportedCertificates(); - if (supported_cert & OEMCrypto_Supports_RSA_CAST) { - cast_receiver = true; - } - if (supported_cert & OEMCrypto_Supports_RSA_3072bit) { - supports_rsa_3072 = true; - } + const uint32_t supported_cert = OEMCrypto_SupportedCertificates(); + if (supported_cert & OEMCrypto_Supports_RSA_CAST) { + cast_receiver = true; + } + if (supported_cert & OEMCrypto_Supports_RSA_3072bit) { + supports_rsa_3072 = true; + } + if (supported_cert & OEMCrypto_Supports_ECC_secp256r1) { + supports_secp256r1 = true; } printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); + printf("supports_rsa_3072 = %s.\n", supports_rsa_3072 ? "true" : "false"); + printf("supports_secp256r1 = %s.\n", supports_secp256r1 ? "true" : "false"); resource_rating = OEMCrypto_ResourceRatingTier(); printf("resource_rating = %u, security level %u.\n", resource_rating, static_cast(OEMCrypto_SecurityLevel())); @@ -101,7 +122,6 @@ void DeviceFeatures::Initialize() { switch (derive_key_method) { case NO_METHOD: printf("NO_METHOD: Cannot derive known session keys.\n"); - // Note: cast_receiver left unchanged because set by user on command line. uses_keybox = false; loads_certificate = false; generic_crypto = false; @@ -140,7 +160,6 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { provisioning_method == OEMCrypto_BootCertificateChain) FilterOut(&filter, "OEMCryptoLoadsCert*"); if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*"); - if (!cast_receiver) FilterOut(&filter, "*CastReceiver*"); if (!supports_cas) FilterOut(&filter, "*CasOnly*"); if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*"); if (provisioning_method @@ -148,15 +167,8 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { if (provisioning_method != OEMCrypto_BootCertificateChain) FilterOut(&filter, "*Prov40*"); if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*"); - if (api_version < 9) FilterOut(&filter, "*API09*"); - if (api_version < 10) FilterOut(&filter, "*API10*"); - if (api_version < 11) FilterOut(&filter, "*API11*"); - if (api_version < 12) FilterOut(&filter, "*API12*"); - if (api_version < 13) FilterOut(&filter, "*API13*"); - if (api_version < 14) FilterOut(&filter, "*API14*"); - if (api_version < 15) FilterOut(&filter, "*API15*"); - if (api_version < 16) FilterOut(&filter, "*API16*"); if (api_version < 17) FilterOut(&filter, "*API17*"); + if (api_version < 18) FilterOut(&filter, "*API18*"); // clang-format on // Some tests may require root access. If user is not root, filter these tests // out. @@ -175,38 +187,32 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { } void DeviceFeatures::PickDerivedKey() { - if (api_version >= 12) { - switch (provisioning_method) { - case OEMCrypto_OEMCertificate: - derive_key_method = TEST_PROVISION_30; - return; - case OEMCrypto_DrmCertificate: - if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { - derive_key_method = LOAD_TEST_RSA_KEY; - } - return; - case OEMCrypto_Keybox: - // Fall through to api_version < 12 case. - break; - case OEMCrypto_BootCertificateChain: - derive_key_method = TEST_PROVISION_40; - return; - case OEMCrypto_ProvisioningError: - printf( - "ERROR: OEMCrypto_GetProvisioningMethod() returns " - "OEMCrypto_ProvisioningError\n"); - // Then fall through to api_version < 12 case. - break; - } - } - if (uses_keybox) { - // If device uses a keybox, try to load the test keybox. - if (OEMCrypto_ERROR_NOT_IMPLEMENTED != - OEMCrypto_LoadTestKeybox(nullptr, 0)) { - derive_key_method = LOAD_TEST_KEYBOX; - } - } else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { - derive_key_method = LOAD_TEST_RSA_KEY; + switch (provisioning_method) { + case OEMCrypto_OEMCertificate: + derive_key_method = TEST_PROVISION_30; + return; + case OEMCrypto_DrmCertificate: + if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { + derive_key_method = LOAD_TEST_RSA_KEY; + } + return; + case OEMCrypto_Keybox: + if (OEMCrypto_ERROR_NOT_IMPLEMENTED != + OEMCrypto_LoadTestKeybox(nullptr, 0)) { + derive_key_method = LOAD_TEST_KEYBOX; + } + return; + case OEMCrypto_BootCertificateChain: + derive_key_method = TEST_PROVISION_40; + return; + case OEMCrypto_ProvisioningError: + printf( + "ERROR: OEMCrypto_GetProvisioningMethod() returns " + "OEMCrypto_ProvisioningError\n"); + if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { + derive_key_method = LOAD_TEST_RSA_KEY; + } + return; } } diff --git a/oemcrypto/test/oec_device_features.h b/oemcrypto/test/oec_device_features.h index a65eef1..ec0a8fc 100644 --- a/oemcrypto/test/oec_device_features.h +++ b/oemcrypto/test/oec_device_features.h @@ -10,7 +10,7 @@ namespace wvoec { // These tests are designed to work for this version: -constexpr unsigned int kCurrentAPI = 17; +constexpr unsigned int kCurrentAPI = 18; // The API version when Core Messages were introduced. constexpr unsigned int kCoreMessagesAPI = 16; // The API version when we stopped encrypting key control blocks. @@ -47,6 +47,7 @@ class DeviceFeatures { bool cast_receiver; // Device supports alternate rsa signature padding. bool usage_table; // Device saves usage information. bool supports_rsa_3072; // Device supports 3072 bit RSA keys. + bool supports_secp256r1; // Device supports secp256r1 ECC keys. bool supports_level_1; // Device supports Level 1 security. uint32_t resource_rating; // Device's resource rating tier. bool supports_crc; // Supported decrypt hash type CRC. diff --git a/oemcrypto/test/oec_key_deriver.h b/oemcrypto/test/oec_key_deriver.h index 4741da4..57d8fc1 100644 --- a/oemcrypto/test/oec_key_deriver.h +++ b/oemcrypto/test/oec_key_deriver.h @@ -19,6 +19,7 @@ namespace wvoec { constexpr size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. constexpr size_t kMaxCoreProvRequest = 150; // Rough estimate. +constexpr size_t kMaxX509CertLength = 4000; // Rough estimate. // This structure will be signed to simulate a provisioning response from the // server. @@ -31,6 +32,15 @@ struct RSAPrivateKeyMessage { uint32_t nonce; }; +// This structure simulates a provisioning 4.0 response from the server. +// However, OEMCrypto doesn't need to load this response, since it doesn't have +// any secrets to be handled. It is just a dummy struct for the tests to +// compile. +struct Prov40CertMessage { + uint8_t device_certificate[kMaxX509CertLength]; + uint32_t nonce; +}; + // Holds an encryption key and can encrypt a provisioning message. It also can // encrypt short buffers using CBC, such as content keys in a license. class Encryptor { diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 7977a7f..efed598 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -7,6 +7,7 @@ #include "oec_session_util.h" +#include #include #include #include @@ -44,6 +45,8 @@ using namespace std; +using testing::AnyOf; + // GTest requires PrintTo to be in the same namespace as the thing it prints, // which is std::vector in this case. namespace std { @@ -58,6 +61,27 @@ using oemcrypto_core_message::features::CoreMessageFeatures; constexpr size_t kTestSubsampleSectionSize = 256; +// Fill objects by consuming a source buffer of fuzzed data. +class FuzzedData { + public: + FuzzedData(const uint8_t* source, size_t source_size) + : source_(source), source_size_(source_size) {} + + // Fill the destination buffer with fuzzed data. + void Fill(void* destination, size_t destination_size) { + if (source_ && destination) { + const size_t fill_size = std::min(source_size_, destination_size); + memcpy(destination, source_, fill_size); + source_ += fill_size; + source_size_ -= fill_size; + } + } + + private: + const uint8_t* source_; + size_t source_size_; +}; + // Encrypt a block of data using CTR mode. void EncryptCTR(const vector& in_buffer, const uint8_t* key, const uint8_t* starting_iv, vector* out_buffer) { @@ -87,8 +111,8 @@ void EncryptCTR(const vector& in_buffer, const uint8_t* key, // the plaintext of that key so that it can encrypt the test data. It resizes // the provided vectors and fills them with the expected and actual decrypt // results. Returns the result of OEMCrypto_DecryptCENC(). -OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, - vector* expected_data, +OEMCryptoResult DecryptCTR(const vector& key_handle, + const uint8_t* key, vector* expected_data, vector* actual_data) { vector encrypted_data(kTestSubsampleSectionSize); expected_data->resize(encrypted_data.size()); @@ -108,7 +132,8 @@ OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; // Decrypt the data - return OEMCrypto_DecryptCENC(session_id, &sample_description, 1, &pattern); + return OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); } } // namespace @@ -241,11 +266,9 @@ RoundTrip:: gen_signature.resize(gen_signature_length); } if (!verify_request || result != OEMCrypto_SUCCESS) return result; - if (global_features.api_version >= kCoreMessagesAPI) { - std::string core_message(reinterpret_cast(data.data()), - core_message_length); - FillAndVerifyCoreRequest(core_message); - } + std::string core_message(reinterpret_cast(data.data()), + core_message_length); + FillAndVerifyCoreRequest(core_message); VerifyRequestSignature(data, gen_signature, core_message_length); return result; } @@ -361,14 +384,6 @@ void ProvisioningRoundTrip::FillAndVerifyCoreRequest( EXPECT_EQ(global_features.api_version, core_request_.api_major_version); EXPECT_EQ(session()->nonce(), core_request_.nonce); EXPECT_EQ(session()->session_id(), core_request_.session_id); - size_t device_id_length = core_request_.device_id.size(); - std::vector device_id(device_id_length); - EXPECT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetDeviceID(device_id.data(), &device_id_length)); - EXPECT_EQ(core_request_.device_id.size(), device_id_length); - std::string device_id_string(reinterpret_cast(device_id.data()), - device_id_length); - EXPECT_EQ(device_id_string, core_request_.device_id); } void ProvisioningRoundTrip::CreateDefaultResponse() { @@ -420,17 +435,13 @@ void ProvisioningRoundTrip:: } void ProvisioningRoundTrip::SignResponse() { - if (global_features.api_version >= kCoreMessagesAPI) { - CoreMessageFeatures features = - CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION); - ASSERT_TRUE( - oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( - features, core_response_, core_request_, - &serialized_core_message_)); - // Resizing for huge core message length unit tests. - serialized_core_message_.resize( - std::max(required_core_message_size_, serialized_core_message_.size())); - } + CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( + features, core_response_, core_request_, &serialized_core_message_)); + // Resizing for huge core message length unit tests. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); // Make the message buffer a just big enough, or the // required size, whichever is larger. const size_t message_size = @@ -459,14 +470,16 @@ void ProvisioningRoundTrip::SignResponse() { } void ProvisioningRoundTrip::InjectFuzzedResponseData(const uint8_t* data, - size_t size UNUSED) { + size_t size) { // Interpreting fuzz data as unencrypted core_response + message_data - const size_t core_response_size = sizeof(ODK_ParsedProvisioning); + FuzzedData fuzzed_data(data, size); + // Copy core_response from data and serialize. - memcpy(&core_response_, data, core_response_size); + fuzzed_data.Fill(&core_response_, sizeof(core_response_)); // Copy provisioning message data into response_data. - memcpy(&response_data_, data + core_response_size, sizeof(response_data_)); + fuzzed_data.Fill(&response_data_, sizeof(response_data_)); + // Set nonce to one from session to pass nonce checks. response_data_.nonce = session()->nonce(); } @@ -498,30 +511,6 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) { return sts; } -#ifdef TEST_OEMCRYPTO_V15 -// If this platform supports v15 functions, then will test with them: -# define OEMCrypto_RewrapDeviceRSAKey_V15 OEMCrypto_RewrapDeviceRSAKey -# define OEMCrypto_RewrapDeviceRSAKey30_V15 OEMCrypto_RewrapDeviceRSAKey30 - -#else -// If this platform does not support v15 functions, we just need to stub these -// out so that the tests compile. -OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30_V15( - OEMCrypto_SESSION, const uint32_t*, const uint8_t*, size_t, const uint8_t*, - size_t, const uint8_t*, uint8_t*, size_t*) { - LOGE("Support for v15 functions not included. Define TEST_OEMCRYPTO_V15."); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey_V15( - OEMCrypto_SESSION, const uint8_t*, size_t, const uint8_t*, size_t, - const uint32_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, - size_t*) { - LOGE("Support for v15 functions not included. Define TEST_OEMCRYPTO_V15."); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} -#endif - template const T* ProvisioningRoundTrip::RemapPointer(const T* response_pointer) const { const uint8_t* original_pointer = @@ -538,33 +527,12 @@ const T* ProvisioningRoundTrip::RemapPointer(const T* response_pointer) const { OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry( Session* session, size_t* wrapped_key_length) { EXPECT_NE(session, nullptr); - if (global_features.api_version >= kCoreMessagesAPI) { - VerifyEncryptAndSignResponseLengths(); - return OEMCrypto_LoadProvisioning( - session->session_id(), encrypted_response_.data(), - encrypted_response_.size(), serialized_core_message_.size(), - response_signature_.data(), response_signature_.size(), - wrapped_rsa_key_.data(), wrapped_key_length); - } else if (global_features.provisioning_method == OEMCrypto_Keybox) { - VerifyEncryptAndSignResponseLengths(); - return OEMCrypto_RewrapDeviceRSAKey_V15( - session->session_id(), encrypted_response_.data(), - encrypted_response_.size(), response_signature_.data(), - response_signature_.size(), RemapPointer(&response_data_.nonce), - RemapPointer(response_data_.rsa_key), - encrypted_response_data_.rsa_key_length, - RemapPointer(response_data_.rsa_key_iv), wrapped_rsa_key_.data(), - wrapped_key_length); - } else { - return OEMCrypto_RewrapDeviceRSAKey30_V15( - session->session_id(), &encrypted_response_data_.nonce, - RemapPointer(response_data_.enc_message_key), - response_data_.enc_message_key_length, - RemapPointer(response_data_.rsa_key), - encrypted_response_data_.rsa_key_length, - RemapPointer(response_data_.rsa_key_iv), wrapped_rsa_key_.data(), - wrapped_key_length); - } + VerifyEncryptAndSignResponseLengths(); + return OEMCrypto_LoadProvisioning( + session->session_id(), encrypted_response_.data(), + encrypted_response_.size(), serialized_core_message_.size(), + response_signature_.data(), response_signature_.size(), + wrapped_rsa_key_.data(), wrapped_key_length); } void ProvisioningRoundTrip::VerifyLoadFailed() { @@ -573,6 +541,68 @@ void ProvisioningRoundTrip::VerifyLoadFailed() { ASSERT_EQ(zero, wrapped_rsa_key_); } +void Provisioning40RoundTrip::PrepareSession(bool is_oem_key) { + const size_t buffer_size = 5000; // Make sure it is large enough. + std::vector public_key(buffer_size); + size_t public_key_size = buffer_size; + std::vector public_key_signature(buffer_size); + size_t public_key_signature_size = buffer_size; + std::vector wrapped_private_key(buffer_size); + size_t wrapped_private_key_size = buffer_size; + OEMCrypto_PrivateKeyType key_type; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_GenerateCertificateKeyPair( + session()->session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type)); + wrapped_private_key.resize(wrapped_private_key_size); + public_key.resize(public_key_size); + + if (is_oem_key) { + wrapped_oem_key_ = wrapped_private_key; + oem_public_key_ = public_key; + oem_key_type_ = key_type; + } else { + wrapped_drm_key_ = wrapped_private_key; + drm_public_key_ = public_key; + drm_key_type_ = key_type; + } +} + +void Provisioning40RoundTrip::FillAndVerifyCoreRequest( + const std::string& core_message_string) { + EXPECT_TRUE( + oemcrypto_core_message::deserialize::CoreProvisioning40RequestFromMessage( + core_message_string, &core_request_)); + EXPECT_EQ(global_features.api_version, core_request_.api_major_version); + EXPECT_EQ(session()->nonce(), core_request_.nonce); + EXPECT_EQ(session()->session_id(), core_request_.session_id); +} + +void Provisioning40RoundTrip::VerifyRequestSignature( + const vector& data, const vector& generated_signature, + size_t /* core_message_length */) { + ASSERT_NO_FATAL_FAILURE( + session()->VerifySignature(data, generated_signature.data(), + generated_signature.size(), kSign_RSASSA_PSS)); +} + +OEMCryptoResult Provisioning40RoundTrip::LoadOEMCertResponse() { + EXPECT_GE(wrapped_oem_key_.size(), 0UL); + return OEMCrypto_InstallOemPrivateKey( + session()->session_id(), oem_key_type_, + reinterpret_cast(wrapped_oem_key_.data()), + wrapped_oem_key_.size()); +} + +OEMCryptoResult Provisioning40RoundTrip::LoadDRMCertResponse() { + EXPECT_GE(wrapped_drm_key_.size(), 0UL); + return OEMCrypto_LoadDRMPrivateKey(session()->session_id(), drm_key_type_, + wrapped_drm_key_.data(), + wrapped_drm_key_.size()); +} + void LicenseRoundTrip::VerifyRequestSignature( const vector& data, const vector& generated_signature, size_t core_message_length) { @@ -682,11 +712,13 @@ void LicenseRoundTrip::InjectFuzzedTimerLimits( } void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, - size_t size UNUSED) { + size_t size) { // Interpreting fuzz data as unencrypted core_response + message_data - const size_t core_response_size = sizeof(ODK_ParsedLicense); + FuzzedData fuzzed_data(data, size); + // Copy core_response from data. - memcpy(&core_response_, data, core_response_size); + fuzzed_data.Fill(&core_response_, sizeof(core_response_)); + // Maximum number of keys could be kMaxNumKeys(30). key_array_length can be // any random value as it is read from fuzz data. // Key data array(MessageKeyData keys[kMaxNumKeys]) will be looped over @@ -697,10 +729,12 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, if (core_response_.key_array_length > kMaxNumKeys) { core_response_.key_array_length = kMaxNumKeys; } + // For corpus data, this value gets set to 4, but we need to test other // scenarios too, hence reading key_array_length value. set_num_keys(core_response_.key_array_length); ConvertDataToValidBools(&core_response_); + // TODO(b/157520981): Once assertion bug is fixed, for loop can be removed. // Workaround for the above bug: key_data.length and key_id.length are being // used in AES decryption process and are expected to be a multiple of 16. An @@ -721,7 +755,7 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, // Copy response_data from data and set nonce to match one in request to pass // nonce validations. - memcpy(&response_data_, data + core_response_size, sizeof(response_data_)); + fuzzed_data.Fill(&response_data_, sizeof(response_data_)); for (uint32_t i = 0; i < num_keys_; ++i) { response_data_.keys[i].control.nonce = session()->nonce(); } @@ -837,26 +871,22 @@ void LicenseRoundTrip::EncryptResponse(bool force_clear_kcb) { void LicenseRoundTrip::CreateCoreLicenseResponseWithFeatures( const CoreMessageFeatures& features) { - if (api_version_ < kCoreMessagesAPI) { - serialized_core_message_.resize(0); - } else { - if (core_request_.api_major_version == 0) { - // If we don't have a valid request, then we should at least set the - // version number of the request so that CreateCoreLicenseResponse can - // compute the version number of the response. - core_request_.api_major_version = ODK_MAJOR_VERSION; - core_request_.api_minor_version = ODK_MINOR_VERSION; - } - std::string request_hash_string( - reinterpret_cast(request_hash_), sizeof(request_hash_)); - ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( - features, core_response_, core_request_, request_hash_string, - &serialized_core_message_)); - // Resize serialize core message to be just big enough or required core - // message size, whichever is larger. - serialized_core_message_.resize( - std::max(required_core_message_size_, serialized_core_message_.size())); + if (core_request_.api_major_version == 0) { + // If we don't have a valid request, then we should at least set the + // version number of the request so that CreateCoreLicenseResponse can + // compute the version number of the response. + core_request_.api_major_version = ODK_MAJOR_VERSION; + core_request_.api_minor_version = ODK_MINOR_VERSION; } + std::string request_hash_string(reinterpret_cast(request_hash_), + sizeof(request_hash_)); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( + features, core_response_, core_request_, request_hash_string, + &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } void LicenseRoundTrip::SignEncryptedResponse() { @@ -939,22 +969,10 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session, reinterpret_cast(&encrypted_response_data_), reinterpret_cast(&encrypted_response_data_) + sizeof(encrypted_response_data_)); - OEMCryptoResult result; - if (api_version_ < kCoreMessagesAPI) { - result = OEMCrypto_LoadKeys( - session->session_id(), double_message.data(), - encrypted_response_.size(), response_signature_.data(), - response_signature_.size(), core_response_.enc_mac_keys_iv, - core_response_.enc_mac_keys, core_response_.key_array_length, - core_response_.key_array, core_response_.pst, - core_response_.srm_restriction_data, - static_cast(core_response_.license_type)); - } else { - result = OEMCrypto_LoadLicense( - session->session_id(), double_message.data(), - encrypted_response_.size(), serialized_core_message_.size(), - response_signature_.data(), response_signature_.size()); - } + OEMCryptoResult result = OEMCrypto_LoadLicense( + session->session_id(), double_message.data(), encrypted_response_.size(), + serialized_core_message_.size(), response_signature_.data(), + response_signature_.size()); if (verify_keys && result == OEMCrypto_SUCCESS) { // Give the session object a copy of the license truth data so that it can // call SelectKey, use key control information, and so that it has key data @@ -979,7 +997,7 @@ OEMCryptoResult LicenseRoundTrip::ReloadResponse(Session* session) { // This function verifies that the key control block reported by OEMCrypto agree // with the truth key control block. Failures in this function probably -// indicate the OEMCrypto_LoadLicense/LoadKeys did not correctly process the key +// indicate the OEMCrypto_LoadLicense did not correctly process the key // control block. void LicenseRoundTrip::VerifyTestKeys(Session* session) { for (unsigned int i = 0; i < num_keys_; i++) { @@ -1264,15 +1282,16 @@ void EntitledMessage::VerifyDecrypt() { for (unsigned int i = 0; i < num_keys_; i++) { const EntitledContentKeyData* const key_data = &entitled_key_data_[i]; - OEMCryptoResult result = OEMCrypto_SelectKey( + vector key_handle; + OEMCryptoResult result = GetKeyHandleIntoVector( entitled_key_session_, key_data->content_key_id, - key_data->content_key_id_length, OEMCrypto_CipherMode_CENC); + key_data->content_key_id_length, OEMCrypto_CipherMode_CENC, key_handle); ASSERT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; vector expected_data; vector actual_data; - result = DecryptCTR(entitled_key_session_, key_data->content_key_data, - &expected_data, &actual_data); + result = DecryptCTR(key_handle, key_data->content_key_data, &expected_data, + &actual_data); EXPECT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; EXPECT_EQ(actual_data, expected_data) << "For key " << i; } @@ -1283,22 +1302,14 @@ void RenewalRoundTrip::VerifyRequestSignature( size_t core_message_length) { ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, generated_signature.size()); std::vector expected_signature; - if (license_messages_->api_version() < kCoreMessagesAPI) { - // For v15 or earlier, we only sign the message body. Ignore the core - // message. - std::vector subdata(data.begin() + core_message_length, - data.end()); - session()->key_deriver().ClientSignBuffer(subdata, &expected_signature); - } else { - session()->key_deriver().ClientSignBuffer(data, &expected_signature); - } + session()->key_deriver().ClientSignBuffer(data, &expected_signature); ASSERT_EQ(expected_signature, generated_signature); } void RenewalRoundTrip::FillAndVerifyCoreRequest( const std::string& core_message_string) { - if (license_messages_->api_version() < kCoreMessagesAPI || is_release_) { - // For v15 or for a release, we expect that no core request was created. + if (is_release_) { + // For a release we expect that no core request was created. EXPECT_FALSE( oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage( core_message_string, &core_request_)); @@ -1315,17 +1326,9 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest( } void RenewalRoundTrip::CreateDefaultResponse() { - if (license_messages_->api_version() < kCoreMessagesAPI || is_release_) { + if (is_release_) { uint32_t control = 0; uint32_t nonce = 0; - // If this is a v15 device, and a v15 license, and the license used a nonce, - // then the response should require a new nonce, too. - if (global_features.api_version < kCoreMessagesAPI && - (license_messages_->control() & wvoec::kControlNonceEnabled)) { - control = wvoec::kControlNonceEnabled; - session_->GenerateNonce(); - nonce = session_->nonce(); - } // A single key object with no key id should update all keys. constexpr size_t index = 0; response_data_.keys[index].key_id_length = 0; @@ -1347,29 +1350,19 @@ void RenewalRoundTrip::CreateDefaultResponse() { void RenewalRoundTrip::EncryptAndSignResponse() { // Renewal messages are not encrypted. encrypted_response_data_ = response_data_; - // Either create a KeyRefreshObject for a call to RefreshKeys or a core - // response for a call to LoadRenewal. - if (license_messages_->api_version() < kCoreMessagesAPI) { - refresh_object_.key_id = FindSubstring(nullptr, 0); - refresh_object_.key_control_iv = FindSubstring(nullptr, 0); - refresh_object_.key_control = - FindSubstring(&response_data_.keys[0].control, - sizeof(response_data_.keys[0].control)); - serialized_core_message_.resize(0); - } else { - // TODO(b/191724203): Test renewal server has different version from license - // server. - ASSERT_NE(license_messages_, nullptr); - CoreMessageFeatures features = - CoreMessageFeatures::DefaultFeatures(license_messages_->api_version()); - ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( - features, core_request_, renewal_duration_seconds_, - &serialized_core_message_)); - // Resize serialize core message to be just big enough or required core - // message size, whichever is larger. - serialized_core_message_.resize( - std::max(required_core_message_size_, serialized_core_message_.size())); - } + // Create a core response for a call to LoadRenewal. + // TODO(b/191724203): Test renewal server has different version from license + // server. + ASSERT_NE(license_messages_, nullptr); + CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(license_messages_->api_version()); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( + features, core_request_, renewal_duration_seconds_, + &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); // Make the message buffer a just big enough, or the // required size, whichever is larger. const size_t message_size = @@ -1441,17 +1434,10 @@ OEMCryptoResult RenewalRoundTrip::LoadResponse(Session* session) { sizeof(encrypted_response_data_)); } VerifyEncryptAndSignResponseLengths(); - if (license_messages_->api_version() < kCoreMessagesAPI) { - return OEMCrypto_RefreshKeys( - session->session_id(), encrypted_response_.data(), - encrypted_response_.size(), response_signature_.data(), - response_signature_.size(), 1, &refresh_object_); - } else { - return OEMCrypto_LoadRenewal( - session->session_id(), encrypted_response_.data(), - encrypted_response_.size(), serialized_core_message_.size(), - response_signature_.data(), response_signature_.size()); - } + return OEMCrypto_LoadRenewal( + session->session_id(), encrypted_response_.data(), + encrypted_response_.size(), serialized_core_message_.size(), + response_signature_.data(), response_signature_.size()); } std::unordered_map, @@ -1562,29 +1548,27 @@ void Session::GenerateDerivedKeysFromSessionKey() { enc_context); } -void Session::TestDecryptCTR(bool select_key_first, +void Session::TestDecryptCTR(bool get_fresh_key_handle_first, OEMCryptoResult expected_result, size_t key_index) { - OEMCryptoResult select_result = OEMCrypto_SUCCESS; - if (select_key_first) { + OEMCryptoResult getkeyhandle_result = OEMCrypto_SUCCESS; + if (get_fresh_key_handle_first) { // Select the key (from FillSimpleMessage) - select_result = OEMCrypto_SelectKey( - session_id(), license_.keys[key_index].key_id, - license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC); + getkeyhandle_result = GetKeyHandle(key_handle_, key_index); } vector unencrypted_data; vector output_buffer; const OEMCryptoResult decrypt_result = - DecryptCTR(session_id(), license_.keys[key_index].key_data, + DecryptCTR(key_handle_, license_.keys[key_index].key_data, &unencrypted_data, &output_buffer); // We only have a few errors that we test are reported. ASSERT_NO_FATAL_FAILURE( - TestDecryptResult(expected_result, select_result, decrypt_result)) - << "Either SelectKey or DecryptCENC should return " << expected_result - << ", but they returned " << select_result << " and " << decrypt_result - << ", respectively."; + TestDecryptResult(expected_result, getkeyhandle_result, decrypt_result)) + << "Either GetKeyHandle or DecryptCENC should return " << expected_result + << ", but they returned " << getkeyhandle_result << " and " + << decrypt_result << ", respectively."; if (expected_result == OEMCrypto_SUCCESS) { // No error. ASSERT_EQ(unencrypted_data, output_buffer); } else { @@ -1592,44 +1576,85 @@ void Session::TestDecryptCTR(bool select_key_first, } } +void Session::TestDecryptEntitled(OEMCryptoResult expected_result, + OEMCrypto_SESSION session_id, + const uint8_t* content_key_id, + size_t content_key_id_length) { + // Select the key (from FillSimpleMessage) + const OEMCryptoResult getkeyhandle_result = + GetKeyHandleIntoVector(session_id, content_key_id, content_key_id_length, + OEMCrypto_CipherMode_CENC, key_handle_); + + vector unencrypted_data; + vector output_buffer; + vector encrypted_data(kTestSubsampleSectionSize); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description)); + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + EncryptCTR(unencrypted_data, content_key_id, &sample_description.iv[0], + &encrypted_data); + // Try to decrypt the data with oemcrypto session id. + const OEMCryptoResult decrypt_result = OEMCrypto_DecryptCENC( + key_handle_.data(), key_handle_.size(), &sample_description, 1, &pattern); + + // We only have a few errors that we test are reported. + ASSERT_NO_FATAL_FAILURE( + TestDecryptResult(expected_result, getkeyhandle_result, decrypt_result)) + << "Either SelectKey or DecryptCENC should return " << expected_result + << ", but they returned " << getkeyhandle_result << " and " + << decrypt_result << ", respectively."; +} + +OEMCryptoResult Session::GetKeyHandle(vector& key_handle, + size_t key_index, + OEMCryptoCipherMode cipher_mode) { + return GetKeyHandleIntoVector(session_id(), license_.keys[key_index].key_id, + license_.keys[key_index].key_id_length, + cipher_mode, key_handle); +} + void Session::TestDecryptResult(OEMCryptoResult expected_result, - OEMCryptoResult actual_select_result, + OEMCryptoResult actual_getkeyhandle_result, OEMCryptoResult actual_decrypt_result) { // In most cases, we expect the result to come from either the select key or // from the decrypt call. if (expected_result == OEMCrypto_SUCCESS) { // No error. - ASSERT_EQ(OEMCrypto_SUCCESS, actual_select_result); + ASSERT_EQ(OEMCrypto_SUCCESS, actual_getkeyhandle_result); ASSERT_EQ(OEMCrypto_SUCCESS, actual_decrypt_result); } else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED || expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP || expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) { // Key expired or output problems may be reported from select key or // decrypt, but must be reported. - ASSERT_TRUE(actual_select_result == expected_result || + ASSERT_TRUE(actual_getkeyhandle_result == expected_result || actual_decrypt_result == expected_result); - } else if (expected_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION && - global_features.api_version >= kCoreMessagesAPI) { + } else if (expected_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION) { // OEMCrypto is allowed to report either this warning or // OEMCrypto_ERROR_INSUFFICIENT_HDCP depending on if it can disable // restricted displays. ASSERT_TRUE( - actual_select_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION || - actual_select_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP || + actual_getkeyhandle_result == + OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION || + actual_getkeyhandle_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP || actual_decrypt_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION || actual_decrypt_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP); } else { // OEM's can fine tune other error codes for debugging. - ASSERT_TRUE(actual_select_result != OEMCrypto_SUCCESS || + ASSERT_TRUE(actual_getkeyhandle_result != OEMCrypto_SUCCESS || actual_decrypt_result != OEMCrypto_SUCCESS); } } -void Session::TestSelectExpired(size_t key_index) { +void Session::TestGetKeyHandleExpired(size_t key_index) { if (global_features.api_version >= 13) { - OEMCryptoResult status = OEMCrypto_SelectKey( - session_id(), license().keys[key_index].key_id, - license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC); - // It is OK for SelectKey to succeed with an expired key, but if there is + OEMCryptoResult status = GetKeyHandle(key_handle_, key_index); + // It is OK for GetKeyHandle to succeed with an expired key, but if there is // an error, it must be OEMCrypto_ERROR_KEY_EXIRED. if (status != OEMCrypto_SUCCESS) { ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); @@ -1789,8 +1814,15 @@ void Session::VerifyRsaSignature(const vector& message, const util::RsaSignatureAlgorithm algorithm = padding_scheme == kSign_RSASSA_PSS ? util::kRsaPssDefault : util::kRsaPkcs1Cast; - const OEMCryptoResult result = public_rsa_->VerifySignature( - message.data(), message.size(), signature, signature_length, algorithm); + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1; + if (algorithm == util::kRsaPssDefault) { + ASSERT_THAT( + OEMCrypto_GetSignatureHashAlgorithm(session_id(), &hash_algorithm), + AnyOf(OEMCrypto_SUCCESS, OEMCrypto_ERROR_NOT_IMPLEMENTED)); + } + const OEMCryptoResult result = + public_rsa_->VerifySignature(message.data(), message.size(), signature, + signature_length, algorithm, hash_algorithm); ASSERT_EQ(result, OEMCrypto_SUCCESS) << "RSA signature check failed"; } @@ -2051,4 +2083,25 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length, AppendToFile(file_name, reinterpret_cast(data.data()), data.size()); } + +OEMCryptoResult GetKeyHandleIntoVector(OEMCrypto_SESSION session, + const uint8_t* key_id, + size_t key_id_length, + OEMCryptoCipherMode cipher_mode, + vector& key_handle) { + size_t key_handle_length = 0; + const OEMCryptoResult result = OEMCrypto_GetKeyHandle( + session, key_id, key_id_length, cipher_mode, nullptr, &key_handle_length); + if (result == OEMCrypto_SUCCESS) { + LOGE( + "OEMCrypto_GetKeyHandle returned SUCCESS despite getting no key handle " + "buffer"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } else if (result != OEMCrypto_ERROR_SHORT_BUFFER) { + return result; + } + key_handle.resize(key_handle_length); + return OEMCrypto_GetKeyHandle(session, key_id, key_id_length, cipher_mode, + key_handle.data(), &key_handle_length); +} } // namespace wvoec diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index bd67d58..cdf7642 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -40,7 +41,7 @@ namespace wvoec { // OEMCrypto Fuzzing: Set max signture length to 1mb. const size_t MB = 1024 * 1024; -// Make sure this is larger than kMaxKeysPerSession, in oemcrypto_test.cpp +// Make sure this is larger than kMaxKeysPerSession. constexpr size_t kMaxNumKeys = 30; namespace { @@ -305,7 +306,7 @@ class ProvisioningRoundTrip size_t* wrapped_key_length); // This takes a pointer in the response_data_ and remaps it to the same // pointer within the encrypted message. This is used for backwards - // compatibliity testing, so that a v15 oemcrypto will accept range checks. + // compatibility testing, so that a v15 oemcrypto will accept range checks. template const T* RemapPointer(const T* response_pointer) const; @@ -318,6 +319,56 @@ class ProvisioningRoundTrip std::vector wrapped_rsa_key_; }; +class Provisioning40RoundTrip + : public RoundTrip< + /* CoreRequest */ oemcrypto_core_message::ODK_Provisioning40Request, + OEMCrypto_PrepAndSignProvisioningRequest, + /* CoreResponse */ ODK_ParsedProvisioning, + /* ResponseData */ Prov40CertMessage> { + public: + Provisioning40RoundTrip(Session* session) + : RoundTrip(session), allowed_schemes_(kSign_RSASSA_PSS) {} + void PrepareSession(bool is_oem_key); + + // Not used. Use Load*CertResponse() below to load OEM/DRM response + // respectively. + void CreateDefaultResponse() override{}; + void EncryptAndSignResponse() override{}; + OEMCryptoResult LoadResponse(Session* session) override { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + OEMCryptoResult LoadOEMCertResponse(); + OEMCryptoResult LoadDRMCertResponse(); + + const std::vector& wrapped_oem_key() { return wrapped_oem_key_; } + const std::vector& oem_public_key() { return oem_public_key_; } + OEMCrypto_PrivateKeyType oem_key_type() { return oem_key_type_; } + const std::vector& wrapped_drm_key() { return wrapped_drm_key_; } + const std::vector& drm_public_key() { return drm_public_key_; } + OEMCrypto_PrivateKeyType drm_key_type() { return drm_key_type_; } + void set_allowed_schemes(uint32_t allowed_schemes) { + allowed_schemes_ = allowed_schemes; + } + + protected: + bool RequestHasNonce() override { return true; } + void VerifyRequestSignature(const vector& data, + const vector& generated_signature, + size_t core_message_length) override; + // Verify the values of the core response. + virtual void FillAndVerifyCoreRequest( + const std::string& core_message_string) override; + + uint32_t allowed_schemes_; + std::vector wrapped_oem_key_; + std::vector oem_public_key_; + OEMCrypto_PrivateKeyType oem_key_type_; + std::vector wrapped_drm_key_; + std::vector drm_public_key_; + OEMCrypto_PrivateKeyType drm_key_type_; +}; + class LicenseRoundTrip : public RoundTrip< /* CoreRequest */ oemcrypto_core_message::ODK_LicenseRequest, @@ -570,12 +621,18 @@ class Session { // and also fill out enc_key_, mac_key_server_, and mac_key_client_. void GenerateDerivedKeysFromSessionKey(); // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption. - void TestDecryptCTR(bool select_key_first = true, + void TestDecryptCTR(bool get_fresh_key_handle_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, size_t key_index = 0); - // Verify that an attempt to select an expired key either succeeds, or gives - // an actionable error code. - void TestSelectExpired(size_t key_index); + // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption + // for entitled sessions. + void TestDecryptEntitled(OEMCryptoResult expected_result = OEMCrypto_SUCCESS, + OEMCrypto_SESSION session = 0, + const uint8_t* content_key_id = nullptr, + size_t content_key_id_length = 0); + // Verify that an attempt to get a key handle for an expired key either + // succeeds or gives an actionable error code. + void TestGetKeyHandleExpired(size_t key_index); // Calls OEMCrypto_GetOEMPublicCertificate and OEMCrypto_LoadOEMPrivateKey and // loads the OEM cert's public rsa key into public_rsa_. void LoadOEMCert(bool verify_cert = false); @@ -586,7 +643,7 @@ class Session { vector* wrapped_key, bool force); // Loads the default test RSA public key into public_rsa_. void SetTestRsaPublicKey(); - // Loads the specified DRM public key into the appropriate key. + // Loads the specified DRM or OEM public key into the appropriate key. // The provided key is serialized as an ASN.1 DER encoded PrivateKeyInfo. void SetPublicKeyFromPrivateKeyInfo(OEMCrypto_PrivateKeyType key_type, const uint8_t* buffer, size_t length); @@ -597,7 +654,7 @@ class Session { // The provided key is serialized as an ASN.1 DER encoded PrivateKeyInfo. void SetEccPublicKeyFromPrivateKeyInfo(const uint8_t* buffer, size_t length); - // Loads the specified DRM public key into the appropriate key. + // Loads the specified DRM or OEM public key into the appropriate key. // The provided key is serialized as an ASN.1 DER encoded SubjectPublicKey. void SetPublicKeyFromSubjectPublicKey(OEMCrypto_PrivateKeyType key_type, const uint8_t* buffer, size_t length); @@ -714,16 +771,29 @@ class Session { void set_license(const MessageData& license) { license_ = license; } + // Gives access to the last key handle used by the Session. Useful if a test + // case uses one of the decrypt test functions above and then wants to perform + // further crypto operations using the same key handle. Also useful if a test + // case needs to inject a specific erroneous key handle into the decrypt test + // functions. + vector& key_handle() { return key_handle_; } + const KeyDeriver& key_deriver() const { return key_deriver_; } void set_mac_keys(const uint8_t* mac_keys) { key_deriver_.set_mac_keys(mac_keys); } + bool IsPublicKeySet() { + return public_rsa_ != nullptr || public_ec_ != nullptr; + } private: + OEMCryptoResult GetKeyHandle( + vector& key_handle, size_t key_index = 0, + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CENC); // This compares the actual result with the expected result. If OEMCrypto is // an older version, we allow it to report an equivalent error code. void TestDecryptResult(OEMCryptoResult expected_result, - OEMCryptoResult actual_select_result, + OEMCryptoResult actual_getkeyhandle_result, OEMCryptoResult actual_decryt_result); bool open_ = false; @@ -749,6 +819,7 @@ class Session { static std::mutex ephemeral_key_map_lock_; vector pst_report_buffer_; MessageData license_ = {}; + vector key_handle_; vector encrypted_usage_entry_; uint32_t usage_entry_number_ = 0; @@ -766,6 +837,18 @@ template void GetDefaultRequestSignatureAndCoreMessageLengths( uint32_t& session_id, const size_t& small_size, size_t* gen_signature_length, size_t* core_message_length); +// Loads the key matching the given |key_id| into the |session| in OEMCrypto for +// the given |cipher_mode| and returns a handle to that key. This function +// handles negotiating the size of the |key_handle| buffer. For non-bypassing +// systems, this is equivalent to the old SelectKey call and will deselect any +// previous keys selected in the session. For bypassing systems, multiple key +// handles may be valid simultaneously, but this call may invalidate any +// previous handles. +OEMCryptoResult GetKeyHandleIntoVector(OEMCrypto_SESSION session, + const uint8_t* key_id, + size_t key_id_length, + OEMCryptoCipherMode cipher_mode, + vector& key_handle); } // namespace wvoec #endif // CDM_OEC_SESSION_UTIL_H_ diff --git a/oemcrypto/test/oemcrypto_basic_test.cpp b/oemcrypto/test/oemcrypto_basic_test.cpp new file mode 100644 index 0000000..719af19 --- /dev/null +++ b/oemcrypto/test/oemcrypto_basic_test.cpp @@ -0,0 +1,655 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "oemcrypto_basic_test.h" + +#include "clock.h" +#include "jsmn.h" +#include "log.h" +#include "oemcrypto_corpus_generator_helper.h" +#include "oemcrypto_resource_test.h" +#include "test_sleep.h" + +namespace wvoec { +void OEMCryptoClientTest::SetUp() { + ::testing::Test::SetUp(); + wvutil::TestSleep::SyncFakeClock(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + const OEMCryptoResult api_status = OEMCrypto_SetMaxAPIVersion(kCurrentAPI); + OEMCrypto_EnterTestMode(); + if (api_status != OEMCrypto_SUCCESS && + api_status != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + // Log error, but continue assuming no error. + LOGE("OEMCrypto_SetMaxAPIVersion returned %d", api_status); + } +} + +void OEMCryptoClientTest::TearDown() { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); +} + +const uint8_t* OEMCryptoClientTest::find(const vector& message, + const vector& substring) { + vector::const_iterator pos = search( + message.begin(), message.end(), substring.begin(), substring.end()); + if (pos == message.end()) { + return nullptr; + } + return &(*pos); +} + +OEMCryptoResult OEMCryptoClientTest::CopyBuffer( + OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer, + size_t input_buffer_size, + const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, + uint8_t subsample_flags) { + if (ShouldGenerateCorpus() && input_buffer != nullptr && + dest_buffer_descriptor != nullptr) { + const std::string file_name = + GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); + + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + fuzzed_structure.dest_buffer_desc.type = dest_buffer_descriptor->type; + switch (fuzzed_structure.dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.direct.is_video; + break; + } + fuzzed_structure.subsample_flags = subsample_flags; + + // Corpus for copy buffer fuzzer should be in the format: + // (dest_buffer_descriptor | subsample_flags | input_buffer). + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(&input_buffer), + input_buffer_size); + } + return OEMCrypto_CopyBuffer(session, input_buffer, input_buffer_size, + dest_buffer_descriptor, subsample_flags); +} + +const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { + switch (value) { + case HDCP_NONE: + return "No HDCP supported, no secure data path"; + case HDCP_V1: + return "HDCP version 1.x"; + case HDCP_V1_0: + return "HDCP version 1.0"; + case HDCP_V1_1: + return "HDCP version 1.1"; + case HDCP_V1_2: + return "HDCP version 1.2"; + case HDCP_V1_3: + return "HDCP version 1.3"; + case HDCP_V1_4: + return "HDCP version 1.4"; + case HDCP_V2: + return "HDCP version 2.0"; + case HDCP_V2_1: + return "HDCP version 2.1"; + case HDCP_V2_2: + return "HDCP version 2.2"; + case HDCP_V2_3: + return "HDCP version 2.3"; + case HDCP_NO_DIGITAL_OUTPUT: + return "No HDCP device attached/using local display with secure path"; + default: + return ""; + } +} + +// Return a printable string from data. If all the characters are printable, +// then just use the string. Otherwise, convert to hex. +std::string MaybeHex(const uint8_t* data, size_t length) { + for (size_t i = 0; i < length; i++) { + if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); + } + return std::string(reinterpret_cast(data), length); +} +std::string MaybeHex(const std::vector& data) { + return MaybeHex(data.data(), data.size()); +} + +/// @addtogroup basic +/// @{ + +TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { + Session s; + s.open(); + OEMCrypto_DestBufferDesc output_descriptor; + int secure_fd = kHugeRandomNumber; + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, + secure_fd)); + s.close(); +} + +/** + * Verifies initialization and logs version information. + * This test is first, because it might give an idea why other + * tests are failing when the device has the wrong keybox installed. + * + * The log message should be updated by Widevine with every release so that it + * is easier to verify which version of the tests a partner is running. Widevine + * should change the API version number when the API changes, but the unit tests + * might be updated more frequently, and are only tracked by the date of the + * last change. + */ +TEST_F(OEMCryptoClientTest, VersionNumber) { + const std::string log_message = + "OEMCrypto unit tests for API 18.1. Tests last updated 2023-03-08"; + cout << " " << log_message << "\n"; + cout << " " + << "These tests are part of Android U." + << "\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, 18); + EXPECT_EQ(ODK_MINOR_VERSION, 1); + EXPECT_EQ(kCurrentAPI, static_cast(ODK_MAJOR_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; + uint32_t version = OEMCrypto_APIVersion(); + uint32_t minor_version = OEMCrypto_MinorAPIVersion(); + cout << " OEMCrypto API version is " << version << "." + << minor_version << endl; + if (OEMCrypto_SupportsUsageTable()) { + cout << " OEMCrypto supports usage tables" << endl; + } else { + cout << " OEMCrypto does not support usage tables" << endl; + } + if (version >= 15) { + const uint32_t tier = OEMCrypto_ResourceRatingTier(); + cout << " Resource Rating Tier: " << tier << endl; + } + if (version >= 17) { + OEMCryptoResult sts = OEMCrypto_ProductionReady(); + if (sts != OEMCrypto_SUCCESS) { + LOGW("Device is not production ready, returns %d", sts); + } + sts = OEMCrypto_SUCCESS; + std::string build_info; + size_t buf_length = 0; + sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + build_info.resize(buf_length); + sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + if (build_info.size() != buf_length) { + build_info.resize(buf_length); + } + cout << " BuildInformation: " << build_info << endl; + OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport(); + cout << " WatermarkingSupport: " << support << endl; + } + ASSERT_GE(version, 8u); + ASSERT_LE(version, kCurrentAPI); +} + +/** + * The resource rating is a number from 1 to 4. The first three levels + * were initially defined in API 15 and they were expanded in API 16. + */ +TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) { + ASSERT_GE(OEMCrypto_ResourceRatingTier(), 1u); + ASSERT_LE(OEMCrypto_ResourceRatingTier(), 4u); +} + +/** + * OEMCrypto must declare what type of provisioning scheme it uses. + */ +TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { + OEMCrypto_ProvisioningMethod provisioning_method = + OEMCrypto_GetProvisioningMethod(); + cout << " Provisioning method = " + << ProvisioningMethodName(provisioning_method) << endl; + ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method); +} + +TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) { + OEMCryptoResult sts; + OEMCrypto_HDCP_Capability current, maximum; + sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + printf(" Current HDCP Capability: 0x%02x = %s.\n", + static_cast(current), HDCPCapabilityAsString(current)); + printf(" Maximum HDCP Capability: 0x%02x = %s.\n", + static_cast(maximum), HDCPCapabilityAsString(maximum)); +} + +TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { + // This just tests some trivial functionality of the SRM update functions. + uint16_t version = 0; + OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version); + if (current_result == OEMCrypto_SUCCESS) { + printf(" Current SRM Version: %d.\n", version); + EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr)); + } else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) { + printf(" Current SRM Status: Local Display Only.\n"); + } else { + EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result); + } +} + +TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) { + OEMCryptoResult sts; + std::string build_info; + sts = OEMCrypto_BuildInformation(&build_info[0], nullptr); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); + size_t buf_length = 0; + sts = OEMCrypto_BuildInformation(nullptr, &buf_length); + // Previous versions of the test expected the wrong error code. + // Although OEMCrypto_ERROR_INVALID_CONTEXT is still accepted by + // the tests, vendors should return OEMCrypto_ERROR_SHORT_BUFFER if + // |buffer| is null and |buf_length| is zero, assigning + // the correct length to |buf_length|. + // TODO(231514699): Remove case for ERROR_INVALID_CONTEXT. + ASSERT_TRUE(OEMCrypto_ERROR_SHORT_BUFFER == sts || + OEMCrypto_ERROR_INVALID_CONTEXT == sts); + if (sts == OEMCrypto_ERROR_INVALID_CONTEXT) { + printf( + "Warning: OEMCrypto_BuildInformation should return " + "ERROR_SHORT_BUFFER.\n"); + } + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + constexpr size_t kZero = 0; + ASSERT_GT(buf_length, kZero); + } +} + +TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { + std::string build_info; + OEMCryptoResult sts = OEMCrypto_BuildInformation(&build_info[0], nullptr); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); + size_t buf_length = 0; + // OEMCrypto must allow |buffer| to be null so long as |buffer_length| + // is provided and initially set to zero. + sts = OEMCrypto_BuildInformation(nullptr, &buf_length); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + build_info.resize(buf_length); + const size_t max_final_size = buf_length; + sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_LE(buf_length, max_final_size); + build_info.resize(buf_length); + + jsmn_parser p; + jsmn_init(&p); + std::vector tokens; + int32_t num_tokens = + jsmn_parse(&p, build_info.c_str(), build_info.size(), nullptr, 0); + EXPECT_GT(num_tokens, 0) + << "Failed to parse BuildInformation as JSON, parse returned " + << num_tokens << "for following build info: " << build_info; + + tokens.resize(num_tokens); + jsmn_init(&p); + int32_t jsmn_result = jsmn_parse(&p, build_info.c_str(), build_info.size(), + tokens.data(), num_tokens); + EXPECT_GE(jsmn_result, 0) + << "Failed to parse BuildInformation as JSON, parse returned " + << jsmn_result << "for following build info: " << build_info; + + std::map expected; + expected["soc_vendor"] = JSMN_STRING; + expected["soc_model"] = JSMN_STRING; + expected["ta_ver"] = JSMN_STRING; + expected["uses_opk"] = JSMN_PRIMITIVE; + expected["tee_os"] = JSMN_STRING; + expected["tee_os_ver"] = JSMN_STRING; + + // for values in token + // build string from start,end + // check for existence in map + // check if value matches expectation + // remove from map + for (int i = 0; i < jsmn_result; i++) { + jsmntok_t token = tokens[i]; + std::string key = build_info.substr(token.start, token.end - token.start); + if (expected.find(key) != expected.end()) { + EXPECT_EQ(expected.find(key)->second, tokens[i + 1].type) + << "Type is incorrect for key " << key; + expected.erase(key); + } + } + + // if map is not empty, return false + if (expected.size() > 0) { + std::string missing; + for (auto e : expected) { + missing.append(e.first); + missing.append(" "); + } + FAIL() << "JSON does not contain all required keys. Missing keys: [" + << missing << "] in string " << build_info; + } +} + +TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { + size_t sessions_count; + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); + ASSERT_EQ(0u, sessions_count); + size_t maximum; + OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + printf(" Max Number of Sessions: %zu.\n", maximum); + size_t required_max = GetResourceValue(kMaxConcurrentSession); + ASSERT_GE(maximum, required_max); +} + +TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) { + const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); + printf(" Max Usage Table Size: %zu.\n", maximum); + // A maximum of 0 means the table is constrained by dynamic memory allocation. + if (maximum > 0) { + ASSERT_GE(maximum, RequiredUsageSize()); + } +} + +// +// initialization tests +// +TEST_F(OEMCryptoClientTest, NormalInitTermination) { + // Should be able to terminate OEMCrypto, and then restart it. + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + (void)OEMCrypto_SetMaxAPIVersion(kCurrentAPI); + (void)OEMCrypto_EnterTestMode(); +} + +TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) { + OEMCryptoResult sts; + OEMCrypto_DTCP2_Capability capability; + sts = OEMCrypto_GetDTCP2Capability(&capability); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + switch (capability) { + case OEMCrypto_NO_DTCP2: + printf(" Current DTCP Support: DTCP2 not supported.\n"); + break; + case OEMCrypto_DTCP2_V1: + printf( + " Current DTCP Support: Version 1 (or higher) of " + "DTCP2 is supported.\n"); + break; + } +} + +// +// Session Tests +// +TEST_F(OEMCryptoClientTest, NormalSessionOpenClose) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.close()); +} + +TEST_F(OEMCryptoClientTest, TwoSessionsOpenClose) { + Session s1; + Session s2; + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(s1.close()); + ASSERT_NO_FATAL_FAILURE(s2.close()); +} + +// This test verifies that OEMCrypto can open approximately as many sessions as +// it claims. +TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) { + size_t sessions_count; + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); + ASSERT_EQ(0u, sessions_count); + size_t max_sessions; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetMaxNumberOfSessions(&max_sessions)); + // We expect OEMCrypto implementations support at least this many sessions. + size_t required_number = GetResourceValue(kMaxConcurrentSession); + ASSERT_GE(max_sessions, required_number); + // We allow GetMaxNumberOfSessions to return an estimate. This tests with a + // pad of 5%. Even if it's just an estimate, we still require 8 sessions. + size_t max_sessions_with_pad = max(max_sessions * 19 / 20, required_number); + vector sessions; + // Limit the number of sessions for testing. + const size_t kMaxNumberOfSessionsForTesting = 0x100u; + for (size_t i = 0; i < kMaxNumberOfSessionsForTesting; i++) { + OEMCrypto_SESSION session_id; + OEMCryptoResult sts = OEMCrypto_OpenSession(&session_id); + // GetMaxNumberOfSessions might be an estimate. We allow OEMCrypto to report + // a max that is less than what is actually supported. Assume the number + // returned is |max|. OpenSessions shall not fail if number of active + // sessions is less than |max|; OpenSessions should fail with + // OEMCrypto_ERROR_TOO_MANY_SESSIONS if too many sessions are open. + if (sts != OEMCrypto_SUCCESS) { + ASSERT_EQ(OEMCrypto_ERROR_TOO_MANY_SESSIONS, sts); + ASSERT_GE(i, max_sessions_with_pad); + break; + } + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); + ASSERT_EQ(i + 1, sessions_count); + sessions.push_back(session_id); + } + for (size_t i = 0; i < sessions.size(); i++) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(sessions[i])); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); + ASSERT_EQ(sessions.size() - i - 1, sessions_count); + } + if (sessions.size() == kMaxNumberOfSessionsForTesting) { + printf( + " MaxSessionsOpenClose: reaches " + "kMaxNumberOfSessionsForTesting(%zu). GetMaxNumberOfSessions = %zu. " + "ERROR_TOO_MANY_SESSIONS not tested.", + kMaxNumberOfSessionsForTesting, max_sessions); + } +} + +TEST_F(OEMCryptoClientTest, GenerateNonce) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + s.GenerateNonce(); +} + +// Prevent a nonce flood even if each nonce is in a different session. +TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { + int error_counter = 0; + const int64_t test_start = wvutil::Clock().GetCurrentTime(); + // More than 200 nonces per second should generate an error. + // To allow for some slop, we actually test for more. + const int flood_cutoff = 200; + const int loop_count = flood_cutoff * 2; + for (int i = 0; i < loop_count; i++) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + s.GenerateNonce(&error_counter); + } + const int64_t test_end = wvutil::Clock().GetCurrentTime(); + int valid_counter = loop_count - error_counter; + // Either oemcrypto should enforce a delay, or it should return an error from + // GenerateNonce -- in either case the number of valid nonces is rate + // limited. We add two seconds to allow for round off error in both + // test_start and test_end. + EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); + error_counter = 0; + // After a pause, we should be able to regenerate nonces. + wvutil::TestSleep::Sleep(2); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + s.GenerateNonce(&error_counter); + EXPECT_EQ(0, error_counter); +} + +// Prevent a nonce flood even if some nonces are in a different session. This +// is different from the test above because there are several session open at +// the same time. We want to make sure you can't get a flood of nonces by +// opening a flood of sessions. +TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { + int request_counter = 0; + int error_counter = 0; + const int64_t test_start = wvutil::Clock().GetCurrentTime(); + // More than 200 nonces per second should generate an error. + // To allow for some slop, we actually test for more. + const int flood_cutoff = 200; + const size_t session_count = GetResourceValue(kMaxConcurrentSession); + const size_t loop_count = 2 * flood_cutoff / session_count + 1; + for (size_t i = 0; i < loop_count; i++) { + std::vector s(session_count); + for (size_t j = 0; j < session_count; j++) { + ASSERT_NO_FATAL_FAILURE(s[j].open()); + request_counter++; + s[j].GenerateNonce(&error_counter); + } + } + const int64_t test_end = wvutil::Clock().GetCurrentTime(); + int valid_counter = request_counter - error_counter; + // Either oemcrypto should enforce a delay, or it should return an error from + // GenerateNonce -- in either case the number of valid nonces is rate + // limited. We add two seconds to allow for round off error in both + // test_start and test_end. + EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); + error_counter = 0; + // After a pause, we should be able to regenerate nonces. + wvutil::TestSleep::Sleep(2); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + s.GenerateNonce(&error_counter); + EXPECT_EQ(0, error_counter); +} + +// This verifies that CopyBuffer works, even before a license has been loaded. +TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + const int kDataSize = 256; + vector input_buffer(kDataSize); + GetRandBytes(input_buffer.data(), input_buffer.size()); + vector output_buffer(kDataSize); + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(input_buffer, output_buffer); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + CopyBuffer(s.session_id(), nullptr, input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = nullptr; + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size() - 1; + ASSERT_NE(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); +} + +// This verifies that CopyBuffer works on the maximum required buffer size. +TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + size_t max_size = GetResourceValue(kMaxSubsampleSize); + vector input_buffer(max_size); + GetRandBytes(input_buffer.data(), input_buffer.size()); + vector output_buffer(max_size); + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(input_buffer, output_buffer); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryCopyBufferForOutOfRangeHandleLength) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; + + size_t buffer_length = KiB; + input_buffer.resize(buffer_length); + int secure_fd; + if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length, + &dest_buffer_descriptor, + &secure_fd) != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return; + } + + dest_buffer_descriptor.buffer.secure.secure_buffer_length = + kHugeInputBufferLength; + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, + secure_fd); +} + +TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) { + uint8_t oemcrypto_invalid_subsample_flag = 85; + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + size_t max_size = GetResourceValue(kMaxSubsampleSize); + vector input_buffer(max_size); + GetRandBytes(input_buffer.data(), input_buffer.size()); + vector output_buffer(max_size); + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_NO_FATAL_FAILURE( + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); +} + +TEST_F(OEMCryptoClientTest, CanLoadTestKeys) { + ASSERT_NE(DeviceFeatures::NO_METHOD, global_features.derive_key_method) + << "Session tests cannot run with out a test keybox or RSA cert."; +} + +/// @} +} // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_basic_test.h b/oemcrypto/test/oemcrypto_basic_test.h new file mode 100644 index 0000000..2cbe235 --- /dev/null +++ b/oemcrypto/test/oemcrypto_basic_test.h @@ -0,0 +1,41 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_BASIC_TEST_ +#define CDM_OEMCRYPTO_BASIC_TEST_ + +#include + +#include + +#include "OEMCryptoCENC.h" +#include "oemcrypto_session_tests_helper.h" + +namespace wvoec { + +const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value); + +std::string MaybeHex(const uint8_t* data, size_t length); +std::string MaybeHex(const std::vector& data); + +/** Tests for just basic client functionality. */ +class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { + protected: + OEMCryptoClientTest() {} + + void SetUp() override; + void TearDown() override; + const uint8_t* find(const std::vector& message, + const std::vector& substring); + OEMCryptoResult CopyBuffer( + OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer, + size_t input_buffer_size, + const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, + uint8_t subsample_flags); +}; +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_BASIC_TEST_ diff --git a/oemcrypto/test/oemcrypto_decrypt_test.cpp b/oemcrypto/test/oemcrypto_decrypt_test.cpp new file mode 100644 index 0000000..22c810c --- /dev/null +++ b/oemcrypto/test/oemcrypto_decrypt_test.cpp @@ -0,0 +1,686 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "oemcrypto_decrypt_test.h" + +#include "test_sleep.h" + +using ::testing::Combine; +using ::testing::Range; +using ::testing::Values; + +namespace wvoec { + +// Cannot decrypt without first getting a key handle. +TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutGettingAHandle) { + 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()); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// Cannot decrypt with an old key handle. +TEST_P(OEMCryptoLicenseTest, FailDecryptWithOldKeyHandle) { + Session donor_session; + LicenseRoundTrip license_messages2(&donor_session); + ASSERT_NO_FATAL_FAILURE(donor_session.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&donor_session)); + ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages2.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages2.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages2.LoadResponse()); + ASSERT_NO_FATAL_FAILURE(donor_session.TestDecryptCTR()); + + 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()); + + // Inject the donor session's key handle into |session_| and then close the + // donor, which should render the handle invalid. + session_.key_handle() = donor_session.key_handle(); + donor_session.close(); + + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// SelectKey should fail if we attempt to select a key that has not been loaded. +// Also, the error should be NO_CONTENT_KEY. +// This test should pass for v15 devices, except that the exact error code was +// not specified until v16. +TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI16) { + 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()); + + const char* key_id = "no_key"; + vector key_handle; + OEMCryptoResult sts = GetKeyHandleIntoVector( + session_.session_id(), reinterpret_cast(key_id), + strlen(key_id), OEMCrypto_CipherMode_CENC, key_handle); + if (sts != OEMCrypto_SUCCESS) { + EXPECT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, sts); + } else { + // Delayed error code. If select key was a success, then we should + // eventually see the error when we decrypt. + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Generate test data + for (size_t i = 0; i < in_buffer.size(); i++) in_buffer[i] = i % 256; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_EQ(sts, OEMCrypto_ERROR_NO_CONTENT_KEY); + } +} + +// 'cens' mode is no longer supported in v16 +TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) { + 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()); + + vector key_handle; + OEMCryptoResult sts; + sts = GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Create a non-zero pattern to indicate this is 'cens' + OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); +} + +// 'cbc1' mode is no longer supported in v16 +TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) { + 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()); + + vector key_handle; + OEMCryptoResult sts; + sts = GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CBCS, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Create a zero pattern to indicate this is 'cbc1' + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); +} + +TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { + 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()); + + vector key_handle; + OEMCryptoResult sts; + sts = GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CBCS, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + subsample_description.block_offset = 5; // Any value 1-15 will do. + + // Create a non-zero pattern to indicate this is 'cbcs'. + OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); +} + +TEST_P(OEMCryptoLicenseTest, RejectOversizedBlockOffset) { + 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()); + + vector key_handle; + OEMCryptoResult sts; + sts = GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + subsample_description.block_offset = 0xFF; // Anything 16+ + + // Create a zero pattern to indicate this is 'cenc'. + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + + // Try again with the minimum invalid value + subsample_description.block_offset = 16; + sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); +} + +TEST_P(OEMCryptoSessionTestDecryptWithHDCP, DecryptAPI09) { + // Test parameterized by HDCP version. + DecryptWithHDCP(static_cast(GetParam())); +} +INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, + Range(1, 6)); + +// If the license does not allow a hash, then we should not compute one. +TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { + uint32_t hash_type = OEMCrypto_SupportsDecryptHash(); + // If hash is not supported, or is vendor defined, don't try to test it. + if (hash_type != OEMCrypto_CRC_Clear_Buffer) return; + + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t frame_number = 1; + uint32_t hash = 42; + // It is OK to set the hash before loading the keys + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_SetDecryptHash(session_.session_id(), frame_number, + reinterpret_cast(&hash), + sizeof(hash))); + // It is OK to select the key and decrypt. + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); + // But the error code should be bad. + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_GetHashErrorCode(session_.session_id(), &frame_number)); +} + +// This test verifies OEMCrypto_SetDecryptHash for out of range frame number. +TEST_P(OEMCryptoLicenseTest, DecryptHashForOutOfRangeFrameNumber) { + uint32_t frame_number = kHugeRandomNumber; + uint32_t hash = 42; + ASSERT_NO_FATAL_FAILURE(OEMCrypto_SetDecryptHash( + session_.session_id(), frame_number, + reinterpret_cast(&hash), sizeof(hash))); +} + +// +// Decrypt Tests -- these test Decrypt CTR mode only. +// +TEST_P(OEMCryptoLicenseTest, Decrypt) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.core_response() + .timer_limits.total_playback_duration_seconds = kDuration; + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); +} + +// Verify that a zero duration means infinite license duration. +TEST_P(OEMCryptoLicenseTest, DecryptZeroDuration) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.core_response() + .timer_limits.total_playback_duration_seconds = 0; + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, SingleLargeSubsample) { + // This subsample size is larger than a few encrypt/skip patterns. Most + // test cases use a pattern length of 160, so we'll run through at least two + // full patterns if we have more than 320 -- round up to 400. + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 400}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// When the pattern length is 10 blocks, there is a discrepancy between the +// HLS and the CENC standards for samples of size 160*N+16, for N = 1, 2, 3... +// We require the CENC standard for OEMCrypto, and let a layer above us break +// samples into pieces if they wish to use the HLS standard. +TEST_P(OEMCryptoSessionTestsDecryptTests, PatternPlusOneBlock) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 160 + 16}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// Test that a single block can be decrypted. +TEST_P(OEMCryptoSessionTestsDecryptTests, OneBlock) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 16}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests the ability to decrypt multiple subsamples with no offset. +// There is no offset within the block, used by CTR mode. +TEST_P(OEMCryptoSessionTestsDecryptTests, NoOffset) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {25, 160}, + {50, 256}, + {25, 160}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests an offset into the block for the second encrypted subsample. +// This should only work for CTR mode, for CBC mode an error is expected in +// the decrypt step. +// If this test fails for CTR mode, then it is probably handling the +// block_offset incorrectly. +TEST_P(OEMCryptoSessionTestsDecryptTests, EvenOffset) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {25, 8}, + {25, 32}, + {25, 50}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + // CTR Mode is self-inverse -- i.e. We can pick the encrypted data and + // compute the unencrypted data. By picking the encrypted data to be all 0, + // it is easier to re-encrypt the data and debug problems. Similarly, we + // pick an iv = 0. + memset(initial_iv_, 0, KEY_IV_SIZE); + TestSample& sample = samples_[0]; // There is only one sample in this test + sample.truth_buffer.assign(sample.description.buffers.input_data_length, 0); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + if (decrypt_inplace_) { + const size_t total_size = sample.description.buffers.input_data_length; + // In case of decrypt_inplace_, encrypted_buffer contains padded bytes + // which is used for buffer overrun validation. Do not copy the padded + // bytes to truth_buffer. + sample.truth_buffer.assign(sample.encrypted_buffer.begin(), + sample.encrypted_buffer.begin() + total_size); + } else { + sample.truth_buffer = + sample.encrypted_buffer; // truth_buffer_ = encrypted zero buffer. + } + // Run EncryptData to re-encrypt this buffer. For CTR mode, we should get + // back to zeros. + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// If the EvenOffset test passes, but this one doesn't, then DecryptCENC might +// be using the wrong definition of block offset. Adding the block offset to +// the block boundary should give you the beginning of the encrypted data. +// This should only work for CTR mode, for CBC mode, the block offset must be +// 0, so an error is expected in the decrypt step. +// Another way to view the block offset is with the formula: +// block_boundary + block_offset = beginning of subsample. +TEST_P(OEMCryptoSessionTestsDecryptTests, OddOffset) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {10, 50}, + {10, 75}, + {10, 75}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests that the algorithm used to increment the counter for +// AES-CTR mode is correct. There are two possible implementations: +// 1) increment the counter as if it were a 128 bit number, +// 2) increment the low 64 bits as a 64 bit number and leave the high bits +// alone. +// For CENC, the algorithm we should use is the second one. OpenSSL defaults to +// the first. If this test is not passing, you should look at the way you +// increment the counter. Look at the example code in ctr128_inc64 above. +// If you start with an IV of 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, after you +// increment twice, you should get 0xFFFFFFFFFFFFFFFF0000000000000000. +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptWithNearWrap) { + memcpy(initial_iv_, + wvutil::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), + KEY_IV_SIZE); + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 256}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests the case where an encrypted sample is not an even number of +// blocks. For CTR mode, the partial block is encrypted. For CBC mode the +// partial block should be a copy of the clear data. +TEST_P(OEMCryptoSessionTestsDecryptTests, PartialBlock) { + // Note: for more complete test coverage, we want a sample size that is in + // the encrypted range for some tests, e.g. (3,7), and in the skip range for + // other tests, e.g. (7, 3). 3*16 < 50 and 7*16 > 50. + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 50}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// Based on the resource rating, OEMCrypto should be able to handle the maximum +// amount of data that can be passed to it. This is the lesser of: +// +// 1) The maximum total sample size +// 2) The maximum number of subsamples multiplied by the maximum subsample size +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) { + const size_t max_sample_size = GetResourceValue(kMaxSampleSize); + const size_t max_subsample_size = GetResourceValue(kMaxSubsampleSize); + const size_t max_num_subsamples = GetResourceValue(kMaxNumberSubsamples); + + // The +1 on this line ensures that, even in cases where max_sample_size is + // not evenly divisible by max_num_subsamples and thus the division gets + // truncated, (max_num_subsamples * subsample_size) will be greater than + // max_sample_size. + const size_t subsample_size = + std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size); + size_t bytes_remaining = max_sample_size; + std::vector subsample_sizes; + while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) { + const size_t this_subsample_size = + std::min(subsample_size, bytes_remaining); + const size_t clear_size = this_subsample_size / 2; + const size_t encrypted_size = this_subsample_size - clear_size; + + subsample_sizes.push_back({clear_size, encrypted_size}); + bytes_remaining -= this_subsample_size; + } + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes(subsample_sizes)); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryCheckDecryptCENCStatusForHugeNumberOfSubSamples) { + size_t number_of_subsamples = 10000; + std::vector subsample_sizes; + while (number_of_subsamples-- > 0) { + subsample_sizes.push_back({100, 100}); + } + SetSubsampleSizes(subsample_sizes); + LoadLicense(); + MakeBuffers(); + EncryptData(); + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + OEMCryptoResult result = + OEMCrypto_DecryptCENC(key_handle_.data(), key_handle_.size(), + sample_descriptions.data(), 1, &pattern_); + LOGD("Large number of subsamples test has return code %d", result); +} + +TEST_P(OEMCryptoSessionTestsDecryptTests, + OEMCryptoMemoryCheckDecryptCENCStatusForHugeSubSample) { + std::vector subsample_sizes; + subsample_sizes.push_back({100000, 100000}); + SetSubsampleSizes(subsample_sizes); + LoadLicense(); + MakeBuffers(); + EncryptData(); + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + OEMCryptoResult result = + OEMCrypto_DecryptCENC(key_handle_.data(), key_handle_.size(), + sample_descriptions.data(), 1, &pattern_); + LOGD("Large subsample test has return code %d", result); +} + +// Based on the resource rating, OEMCrypto should be able to handle the maximum +// subsample size. +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) { + const size_t max = GetResourceValue(kMaxSubsampleSize); + const size_t half_max = max / 2; + // This test assumes that the maximum sample size is always more than three + // times the maximum subsample size. + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {max, 0}, + {0, max}, + {half_max, max - half_max}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// There are probably no frames this small, but we should handle them anyway. +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptSmallBuffer) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {5, 5}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// Test the case where there is only a clear subsample and no encrypted +// subsample. +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptUnencrypted) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {256, 0}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests the ability to decrypt multiple samples at once. +TEST_P(OEMCryptoSessionTestsDecryptTests, MultipleSamples) { + ASSERT_NO_FATAL_FAILURE(SetSampleSizes({ + { + {52, 160}, + {25, 256}, + {25, 320}, + }, + { + {300, 64}, + {50, 160}, + {2, 160}, + {24, 160}, + {128, 256}, + }, + { + {70, 320}, + {160, 160}, + }, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// This tests that calling OEMCrypto_Idle and OEMCrypto_Wake once or multiple +// times doesn't break anything. +TEST_P(OEMCryptoSessionTestsDecryptTests, IdleAndWake) { + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); +} + +// This tests that after an idle and a wake, decryption can continue in an +// open session. +TEST_P(OEMCryptoSessionTestsDecryptTests, ContinueDecryptionAfterIdleAndWake) { + // This subsample size is larger than a few encrypt/skip patterns. Most + // test cases use a pattern length of 160, so we'll run through at least two + // full patterns if we have more than 320 -- round up to 400. + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 400}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); + FreeSecureBuffers(); + // Set state to idle then wake again and try to reencrypt/decrypt + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + +// Used to construct a specific pattern. +constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, + size_t skip) { + return {encrypt, skip}; +} + +INSTANTIATE_TEST_SUITE_P( + CTRTests, OEMCryptoSessionTestsDecryptTests, + Combine(Values(MakePattern(0, 0)), Values(OEMCrypto_CipherMode_CENC), + ::testing::ValuesIn(global_features.GetOutputTypes()))); + +// Decrypt in place for CBC tests was only required in v13. +INSTANTIATE_TEST_SUITE_P( + CBCTestsAPI14, OEMCryptoSessionTestsDecryptTests, + Combine( + Values(MakePattern(3, 7), MakePattern(9, 1), + // HLS edge cases. We should follow the CENC spec, not HLS spec. + MakePattern(1, 9), MakePattern(1, 0), + // AV1 patterns not already covered above. + MakePattern(5, 5), MakePattern(10, 0)), + Values(OEMCrypto_CipherMode_CBCS), + ::testing::ValuesIn(global_features.GetOutputTypes()))); + +// A request to decrypt data to a clear buffer when the key control block +// requires a secure data path. +TEST_P(OEMCryptoLicenseTest, DecryptSecureToClear) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(wvoec::kControlObserveDataPath | + wvoec::kControlDataPathSecure); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// Test that key duration is honored. +TEST_P(OEMCryptoLicenseTest, KeyDuration) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.core_response() + .timer_limits.total_playback_duration_seconds = kDuration; + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); + wvutil::TestSleep::Sleep(kShortSleep); // Should still be valid key. + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false, OEMCrypto_SUCCESS)); + wvutil::TestSleep::Sleep(kLongSleep); // Should be expired key. + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); + ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(0)); +} + +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, + Range(kCurrentAPI - 2, kCurrentAPI + 1)); + +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_decrypt_test.h b/oemcrypto/test/oemcrypto_decrypt_test.h new file mode 100644 index 0000000..9f9b500 --- /dev/null +++ b/oemcrypto/test/oemcrypto_decrypt_test.h @@ -0,0 +1,427 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_DECRYPT_TEST_ +#define CDM_OEMCRYPTO_DECRYPT_TEST_ + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oec_decrypt_fallback_chain.h" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_license_test.h" + +namespace wvoec { + +// Used to test the different HDCP versions. This test is parameterized by the +// required HDCP version in the key control block. +class OEMCryptoSessionTestDecryptWithHDCP : public OEMCryptoSessionTests, + public WithParamInterface { + protected: + void DecryptWithHDCP(OEMCrypto_HDCP_Capability version) { + OEMCryptoResult sts; + OEMCrypto_HDCP_Capability current, maximum; + sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_control((version << wvoec::kControlHDCPVersionShift) | + wvoec::kControlObserveHDCP | + wvoec::kControlHDCPRequired); + 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()); + + if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) || + (current == HDCP_V1 && version >= HDCP_V1_0)) { + if (global_features.api_version >= 16) { + // Can provide either OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION or + // OEMCrypto_ERROR_INSUFFICIENT_HDCP. TestDecryptCTR allows either to be + // reported if OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION is expected. + ASSERT_NO_FATAL_FAILURE( + s.TestDecryptCTR(true, OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION)) + << "Failed when current HDCP = " << HDCPCapabilityAsString(current) + << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) + << ", license HDCP = " << HDCPCapabilityAsString(version); + } else { + ASSERT_NO_FATAL_FAILURE( + s.TestDecryptCTR(true, OEMCrypto_ERROR_INSUFFICIENT_HDCP)) + << "Failed when current HDCP = " << HDCPCapabilityAsString(current) + << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) + << ", license HDCP = " << HDCPCapabilityAsString(version); + } + } else { + ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(true, OEMCrypto_SUCCESS)) + << "Failed when current HDCP = " << HDCPCapabilityAsString(current) + << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) + << ", license HDCP = " << HDCPCapabilityAsString(version); + } + } +}; + +struct SubsampleSize { + size_t clear_size; + size_t encrypted_size; + SubsampleSize(size_t clear, size_t encrypted) + : clear_size(clear), encrypted_size(encrypted) {} +}; + +// Struct for holding the data for one test sample in the decrypt tests. +struct TestSample { + // Encrypted data -- this is input to OEMCrypto, and output from EncryptData. + std::vector encrypted_buffer; + std::vector clear_buffer; // OEMCrypto store clear output here. + std::vector truth_buffer; // Truth data for clear text. + OEMCrypto_SampleDescription description; + std::vector subsamples; + int secure_buffer_fid; +}; + +// A class of tests that test decryption for a variety of patterns and modes. +// This test is parameterized by three parameters: +// 1. The pattern used for pattern decryption. +// 2. The cipher mode for decryption: either CTR or CBC. +// 3. A boolean that determines if decrypt in place should be done. When the +// output buffer is clear, it should be possible for the input and output +// buffers to be the same. +class OEMCryptoSessionTestsDecryptTests + : public OEMCryptoLicenseTestAPI16, + public WithParamInterface> { + protected: + void SetUp() override { + OEMCryptoLicenseTestAPI16::SetUp(); + pattern_ = ::testing::get<0>(GetParam()); + cipher_mode_ = ::testing::get<1>(GetParam()); + decrypt_inplace_ = ::testing::get<2>(GetParam()).decrypt_inplace; + output_buffer_type_ = ::testing::get<2>(GetParam()).type; + verify_crc_ = global_features.supports_crc; + // Pick a random key. + EXPECT_EQ(GetRandBytes(key_, sizeof(key_)), 1); + // Pick a random starting iv. Some tests override this before using it. + EXPECT_EQ(GetRandBytes(initial_iv_, sizeof(initial_iv_)), 1); + } + + void TearDown() override { + FreeSecureBuffers(); + OEMCryptoLicenseTestAPI16::TearDown(); + } + + void SetSubsampleSizes(std::vector subsample_sizes) { + // This is just sugar for having one sample with the given subsamples in it. + SetSampleSizes({subsample_sizes}); + } + + void SetSampleSizes(std::vector> sample_sizes) { + ASSERT_GT(sample_sizes.size(), 0u); + samples_.clear(); + samples_.reserve(sample_sizes.size()); + + // Convert all the size arrays to TestSample structs + for (const std::vector& subsample_sizes : sample_sizes) { + // This could be one line if we had C++17 + samples_.emplace_back(); + TestSample& sample = samples_.back(); + + ASSERT_GT(subsample_sizes.size(), 0u); + sample.subsamples.reserve(subsample_sizes.size()); + + // Convert all the sizes to subsample descriptions and tally the total + // sample size + size_t sample_size = 0; + size_t current_block_offset = 0; + for (const SubsampleSize& size : subsample_sizes) { + sample.subsamples.push_back(OEMCrypto_SubSampleDescription{ + size.clear_size, size.encrypted_size, + 0, // Subsample Flags, to be filled in after the loop + current_block_offset}); + + // Update the rolling variables + sample_size += size.clear_size + size.encrypted_size; + if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { + current_block_offset = + (current_block_offset + size.encrypted_size) % AES_BLOCK_SIZE; + } + } + + // Set the subsample flags now that all the subsamples are processed + sample.subsamples.front().subsample_flags |= OEMCrypto_FirstSubsample; + sample.subsamples.back().subsample_flags |= OEMCrypto_LastSubsample; + + // Set related information on the sample description + sample.description.subsamples = sample.subsamples.data(); + sample.description.subsamples_length = sample.subsamples.size(); + sample.description.buffers.input_data_length = sample_size; + } + } + + // Set up the input buffer and either a clear or secure output buffer for each + // test sample. This should be called after SetSubsampleSizes(). + void MakeBuffers() { + for (TestSample& sample : samples_) { + const size_t total_size = sample.description.buffers.input_data_length; + ASSERT_GT(total_size, 0u); + sample.encrypted_buffer.clear(); + sample.truth_buffer.clear(); + sample.clear_buffer.clear(); + sample.encrypted_buffer.resize(total_size); + sample.truth_buffer.resize(total_size); + for (size_t i = 0; i < total_size; i++) sample.truth_buffer[i] = i % 256; + + OEMCrypto_DestBufferDesc& output_descriptor = + sample.description.buffers.output_descriptor; + output_descriptor.type = output_buffer_type_; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + if (decrypt_inplace_) { + // Add some padding to verify there is no overrun. + sample.encrypted_buffer.resize(total_size + kBufferOverrunPadding, + 0xaa); + output_descriptor.buffer.clear.clear_buffer = + sample.encrypted_buffer.data(); + } else { + // Add some padding to verify there is no overrun. + sample.clear_buffer.resize(total_size + kBufferOverrunPadding, + 0xaa); + output_descriptor.buffer.clear.clear_buffer = + sample.clear_buffer.data(); + } + output_descriptor.buffer.clear.clear_buffer_length = total_size; + break; + + case OEMCrypto_BufferType_Secure: + output_descriptor.buffer.secure.secure_buffer_length = total_size; + ASSERT_EQ(OEMCrypto_AllocateSecureBuffer( + session_.session_id(), total_size, &output_descriptor, + &sample.secure_buffer_fid), + OEMCrypto_SUCCESS); + ASSERT_NE(output_descriptor.buffer.secure.secure_buffer, nullptr); + // It is OK if OEMCrypto changes the maximum size, but there must + // still be enough room for our data. + ASSERT_GE(output_descriptor.buffer.secure.secure_buffer_length, + total_size); + output_descriptor.buffer.secure.offset = 0; + break; + + case OEMCrypto_BufferType_Direct: + output_descriptor.buffer.direct.is_video = false; + break; + } // switch (output_descriptor.type) + } // sample loop + } + + void FreeSecureBuffers() { + for (TestSample& sample : samples_) { + OEMCrypto_DestBufferDesc& output_descriptor = + sample.description.buffers.output_descriptor; + if (output_descriptor.type == OEMCrypto_BufferType_Secure) { + ASSERT_EQ(OEMCrypto_FreeSecureBuffer(session_.session_id(), + &output_descriptor, + sample.secure_buffer_fid), + OEMCrypto_SUCCESS); + } + } + } + + void EncryptData() { + AES_KEY aes_key; + AES_set_encrypt_key(key_, AES_BLOCK_SIZE * 8, &aes_key); + + for (TestSample& sample : samples_) { + uint8_t iv[KEY_IV_SIZE]; // Current IV + memcpy(iv, initial_iv_, KEY_IV_SIZE); + memcpy(sample.description.iv, initial_iv_, KEY_IV_SIZE); + + size_t buffer_index = 0; // byte index into in and out. + size_t block_offset = 0; // byte index into current block. + for (const OEMCrypto_SubSampleDescription& subsample : + sample.subsamples) { + // Copy clear content. + if (subsample.num_bytes_clear > 0) { + memcpy(&sample.encrypted_buffer[buffer_index], + &sample.truth_buffer[buffer_index], subsample.num_bytes_clear); + buffer_index += subsample.num_bytes_clear; + } + + // The IV resets at the start of each subsample in the 'cbcs' schema. + if (cipher_mode_ == OEMCrypto_CipherMode_CBCS) { + memcpy(iv, initial_iv_, KEY_IV_SIZE); + } + + size_t pattern_offset = 0; + const size_t subsample_end = + buffer_index + subsample.num_bytes_encrypted; + while (buffer_index < subsample_end) { + const size_t size = + min(subsample_end - buffer_index, AES_BLOCK_SIZE - block_offset); + const size_t pattern_length = pattern_.encrypt + pattern_.skip; + const bool skip_block = + (pattern_offset >= pattern_.encrypt) && (pattern_length > 0); + if (pattern_length > 0) { + pattern_offset = (pattern_offset + 1) % pattern_length; + } + // CBC mode should just copy a partial block at the end. If there + // is a partial block at the beginning, an error is returned, so we + // can put whatever we want in the output buffer. + if (skip_block || ((cipher_mode_ == OEMCrypto_CipherMode_CBCS) && + (size < AES_BLOCK_SIZE))) { + memcpy(&sample.encrypted_buffer[buffer_index], + &sample.truth_buffer[buffer_index], size); + block_offset = 0; // Next block should be complete. + } else { + if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { + uint8_t aes_output[AES_BLOCK_SIZE]; + AES_encrypt(iv, aes_output, &aes_key); + for (size_t n = 0; n < size; n++) { + sample.encrypted_buffer[buffer_index + n] = + aes_output[n + block_offset] ^ + sample.truth_buffer[buffer_index + n]; + } + if (size + block_offset < AES_BLOCK_SIZE) { + // Partial block. Don't increment iv. Compute next block + // offset. + block_offset = block_offset + size; + } else { + EXPECT_EQ(block_offset + size, + static_cast(AES_BLOCK_SIZE)); + // Full block. Increment iv, and set offset to 0 for next + // block. + ctr128_inc64(1, iv); + block_offset = 0; + } + } else { + uint8_t aes_input[AES_BLOCK_SIZE]; + for (size_t n = 0; n < size; n++) { + aes_input[n] = sample.truth_buffer[buffer_index + n] ^ iv[n]; + } + AES_encrypt(aes_input, &sample.encrypted_buffer[buffer_index], + &aes_key); + memcpy(iv, &sample.encrypted_buffer[buffer_index], + AES_BLOCK_SIZE); + // CBC mode should always start on block boundary. + block_offset = 0; + } + } + buffer_index += size; + } // encryption loop + } // per-subsample loop + } // per-sample loop + } + + void LoadLicense() { + uint32_t control = wvoec::kControlNonceEnabled; + if (verify_crc_) control |= kControlAllowHashVerification; + if (output_buffer_type_ == OEMCrypto_BufferType_Secure) + control |= kControlObserveDataPath | kControlDataPathSecure; + license_messages_.set_control(control); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_response() + .timer_limits.initial_renewal_duration_seconds = kDuration; + memcpy(license_messages_.response_data().keys[0].key_data, key_, + sizeof(key_)); + license_messages_.response_data().keys[0].cipher_mode = cipher_mode_; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_EQ(GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + cipher_mode_, key_handle_), + OEMCrypto_SUCCESS); + } + + void TestDecryptCENC() { ASSERT_EQ(DecryptCENC(), OEMCrypto_SUCCESS); } + + void ValidateDecryptedData() { + for (TestSample& sample : samples_) { + if (sample.description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Clear) { + const size_t total_size = sample.description.buffers.input_data_length; + // To verify there is no buffer overrun after decrypting, look at the + // padded bytes just after the data buffer that was written. It + // should not have changed from the original 0xaa that we set in + // MakeBuffer function. + if (decrypt_inplace_) { + EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size, + sample.encrypted_buffer.end(), 0xaa), + static_cast(kBufferOverrunPadding)) + << "Buffer overrun."; + sample.encrypted_buffer.resize(total_size); // Remove padding. + // We expect encrypted buffer to have been changed by OEMCrypto. + EXPECT_EQ(sample.encrypted_buffer, sample.truth_buffer); + } else { + EXPECT_EQ(std::count(sample.clear_buffer.begin() + total_size, + sample.clear_buffer.end(), 0xaa), + static_cast(kBufferOverrunPadding)) + << "Buffer overrun."; + sample.clear_buffer.resize(total_size); // Remove padding. + EXPECT_EQ(sample.clear_buffer, sample.truth_buffer); + } + } + } + if (verify_crc_) { + uint32_t frame; + ASSERT_EQ(OEMCrypto_GetHashErrorCode(session_.session_id(), &frame), + OEMCrypto_SUCCESS); + } + } + + OEMCryptoResult DecryptCENC() { + // OEMCrypto only supports providing a decrypt hash for one sample. + if (samples_.size() > 1) verify_crc_ = false; + + // If supported, check the decrypt hashes. + if (verify_crc_) { + const TestSample& sample = samples_[0]; + + uint32_t hash = + util::wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size()); + OEMCrypto_SetDecryptHash(session_.session_id(), 1, + reinterpret_cast(&hash), + sizeof(hash)); + } + + // Build an array of just the sample descriptions. + std::vector sample_descriptions; + sample_descriptions.reserve(samples_.size()); + for (TestSample& sample : samples_) { + // This must be deferred until this point in case the test modifies the + // buffer before testing decrypt. + sample.description.buffers.input_data = sample.encrypted_buffer.data(); + // Append to the description array. + sample_descriptions.push_back(sample.description); + } + + // Perform decryption using the test data that was previously set up. + OEMCryptoResult result = DecryptFallbackChain::Decrypt( + key_handle_.data(), key_handle_.size(), sample_descriptions.data(), + sample_descriptions.size(), cipher_mode_, &pattern_); + if (result != OEMCrypto_SUCCESS) return result; + ValidateDecryptedData(); + return result; + } + + // Parameters of test case + OEMCrypto_CENCEncryptPatternDesc pattern_; + OEMCryptoCipherMode cipher_mode_; + bool decrypt_inplace_; // If true, input and output buffers are the same. + OEMCryptoBufferType output_buffer_type_; + + bool verify_crc_; + uint8_t key_[AES_BLOCK_SIZE]; // Encryption Key. + uint8_t initial_iv_[KEY_IV_SIZE]; // Starting IV for every sample. + std::vector samples_; + std::vector key_handle_; +}; + +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_DECRYPT_TEST_ \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_license_test.cpp b/oemcrypto/test/oemcrypto_license_test.cpp new file mode 100644 index 0000000..25cf89b --- /dev/null +++ b/oemcrypto/test/oemcrypto_license_test.cpp @@ -0,0 +1,804 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "oemcrypto_license_test.h" + +#include "platform.h" + +namespace wvoec { + +// Function to test APIs that expect a buffer length as input +// by passing huge buffer lengths up to end_buffer_length and test that the API +// doesn't crash. +void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, + size_t start_buffer_length, + size_t end_buffer_length, + bool check_status) { + OEMCryptoResult sts = OEMCrypto_SUCCESS; + for (size_t buffer_length = start_buffer_length; + buffer_length < end_buffer_length && + (sts == OEMCrypto_SUCCESS || sts == OEMCrypto_ERROR_SHORT_BUFFER || + !check_status); + buffer_length *= 2) { + sts = f(buffer_length); + if (check_status && sts != OEMCrypto_SUCCESS && + sts != OEMCrypto_ERROR_SHORT_BUFFER) { + LOGI("Test exits huge buffer loop for length:%zu, status:%d", + buffer_length, sts); + } + } +} + +// Function to test APIs that expect a buffer length as input +// by passing huge buffer lengths up to kHugeInputBufferLength and test that +// the API doesn't crash. +void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, bool check_status) { + TestHugeLengthDoesNotCrashAPI(f, 1, kHugeInputBufferLength, check_status); +} + +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. +void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) { + const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); + ASSERT_LE(num_keys_per_session, kMaxNumKeys) << "Update test constants."; + std::vector> sessions; + std::vector> licenses; + size_t total_keys = 0; + for (size_t i = 0; total_keys < max_total_keys; i++) { + sessions.push_back(std::unique_ptr(new Session())); + licenses.push_back(std::unique_ptr( + new LicenseRoundTrip(sessions[i].get()))); + const size_t num_keys = + std::min(max_total_keys - total_keys, num_keys_per_session); + licenses[i]->set_num_keys(static_cast(num_keys)); + total_keys += num_keys; + ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); + ASSERT_NO_FATAL_FAILURE(util->InstallTestDrmKey(sessions[i].get())); + ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest()); + } + for (size_t i = 0; i < licenses.size(); i++) { + ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse()); + } + constexpr bool kSelectKeyFirst = true; + for (size_t i = 0; i < licenses.size(); i++) { + for (size_t key_index = 0; key_index < licenses[i]->num_keys(); + key_index++) { + ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( + kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); + } + } + // Second call to decrypt for each session. + for (size_t i = 0; i < licenses.size(); i++) { + for (size_t key_index = 0; key_index < licenses[i]->num_keys(); + key_index++) { + ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( + kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); + } + } +} + +TEST_F(OEMCryptoSessionTestKeyboxTest, TestKeyboxIsValid) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeRequestMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeCoreMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t core_message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(core_message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeSignatureLength) { + // There is a limit of signature length that gets validated. Hence not + // checking status as we would like to test it for all possible signature + // lengths. + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->set_request_signature_size(length); + }, + !kCheckStatus); +} + +// Verify that a license may be signed. +TEST_P(OEMCryptoLicenseTest, SignLicenseRequest) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); +} + +// Verify that a large license request may be signed. +TEST_P(OEMCryptoLicenseTest, SignLargeLicenseRequest) { + const size_t max_size = GetResourceValue(kLargeMessageSize); + license_messages_.set_message_size(max_size); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); +} + +// Verify that a license may be loaded without a nonce. +TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonce) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(0); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); +} + +// Verify that a preloaded license may be loaded without first signing the +// request. This test is important for the preloaded licenses used by ATSC and +// CAS. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) { + if (license_api_version_ > global_features.api_version) { + // We should not attempt to preload a license with an API higher than that + // of OEMCrypto. + license_api_version_ = global_features.api_version; + license_messages_.set_api_version(license_api_version_); + } + license_messages_.set_control(0); + // Notice that we do not call SignAndVerifyRequest -- we do not need a request + // in order to generate a response for a preloaded license. + // The test code uses the core request to create the core response. + license_messages_.core_request().api_major_version = + global_features.api_version; + license_messages_.core_request().api_minor_version = 0; + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + + // Load license in a different session, which did not create the request. + Session session2; + ASSERT_NO_FATAL_FAILURE(session2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session2)); + ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2)); + ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS)); +} + +// Verify that a license may be reloaded without a nonce, but with a nonzero +// rental duration. In order to start the rental clock, we sign a placeholder +// license instead. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequestRentalDuration) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(0); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // It is not recommended for a license without a nonce to have a nonzero + // rental duration. But there are content providers that have licenses with + // this policy. + license_messages_.core_response().timer_limits.rental_duration_seconds = + kDuration; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + + // Load license in a different session, which did not create the request. + Session session2; + ASSERT_NO_FATAL_FAILURE(session2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session2)); + // However, in order to start the rental clock, we have to sign something. So + // we will sign a placeholder license request. + LicenseRoundTrip dummy_license(&session2); + ASSERT_NO_FATAL_FAILURE(dummy_license.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2)); + ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS)); +} + +// Verify that a license may be loaded with a nonce. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonce) { + 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()); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); +} + +// Verify that a second license may not be loaded in a session. +TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonceTwiceAPI16) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(0); + license_messages_.skip_nonce_check(); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + // A second load, should NOT succeed. + ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); +} + +// Verify that a second license may not be loaded in a session. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) { + 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()); + // A second load, should NOT succeed. + ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); +} + +// This tests load license with an 8k license response. +TEST_P(OEMCryptoLicenseTest, LoadKeyLargeBuffer) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + const size_t max_size = GetResourceValue(kLargeMessageSize); + license_messages_.set_message_size(max_size); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +//---------------------------------------------------------------------------// +//---------------------------------------------------------------------------// +// Each of the following LoadKeyWithBadRange_* tests is similar. They verify +// that OEMCrypto_LoadLicense checks the range of all the pointers. It should +// reject a message if the pointer does not point into the message buffer. +//---------------------------------------------------------------------------// +//---------------------------------------------------------------------------// +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().enc_mac_keys.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys_iv) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().enc_mac_keys_iv.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_id) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().key_array[0].key_id.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().key_array[1].key_data.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data_iv) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().key_array[1].key_data_iv.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().key_array[2].key_control.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control_iv) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().key_array[2].key_control_iv.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_pst) { + license_messages_.set_control(wvoec::kControlNonceOrEntry); + license_messages_.set_pst("my_pst"); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // See the comment in LicenseRoundTrip::LoadResponse for why we increment by + // the message size. + license_messages_.core_response().pst.offset += + sizeof(license_messages_.response_data()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + // If we have a pst, then we need a usage entry. + ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} +//---------------------------------------------------------------------------// +//---------------------------------------------------------------------------// + +// Test that LoadKeys fails when a key is loaded with no key control block. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithNullKeyControl) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_response().key_array[2].key_control.offset = 0; + license_messages_.core_response().key_array[2].key_control.length = 0; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +// Verify that LoadKeys fails when a key's nonce is wrong. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadNonce) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + for (unsigned int i = 0; i < license_messages_.num_keys(); i++) + license_messages_.response_data().keys[i].control.nonce ^= 42; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// Verify that LoadKeys fails when the core message's nonce is wrong. +TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce2) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_request().nonce ^= 42; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// Verify that LoadKeys fails when the core message's session is wrong. +TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce3) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_request().session_id++; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// Verify that LoadKeys fails when an attempt is made to use a nonce twice. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithRepeatNonce) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + const uint32_t nonce = session_.nonce(); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + // This is the first attempt. It should succeed. + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + // Now, open a new session and try to load a license with the same nonce. + session_.close(); + ASSERT_NO_FATAL_FAILURE(session_.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session_)); + license_messages_.skip_nonce_check(); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + // Repeat the nonce. + license_messages_.core_request().nonce = nonce; + for (unsigned int i = 0; i < license_messages_.num_keys(); i++) + license_messages_.response_data().keys[i].control.nonce = htonl(nonce); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// This tests that a nonce cannot be used in new session. This is similar to +// the previous test, but does not use the nonce in the first session. The nonce +// should be tied to a session, so generating a nonce in the first session and +// then using it in the second session should fail. +TEST_P(OEMCryptoLicenseTest, LoadKeyNonceReopenSession) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + uint32_t nonce = session_.nonce(); + // Do not use the nonce now. Close session and use it after re-opening. + ASSERT_NO_FATAL_FAILURE(session_.close()); + + // Actually, this isn't the same session. OEMCrypto opens a new session, but + // we are guarding against the possibility that it re-uses the session data + // and might not clear out the nonce correctly. + ASSERT_NO_FATAL_FAILURE(session_.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session_)); + license_messages_.skip_nonce_check(); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_request().nonce = nonce; + for (unsigned int i = 0; i < license_messages_.num_keys(); i++) + license_messages_.response_data().keys[i].control.nonce = htonl(nonce); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// This tests that a nonce cannot be used in wrong session. This is similar to +// the previous test, except we do not close session 1 before we open session 2. +TEST_P(OEMCryptoLicenseTest, LoadKeyNonceWrongSession) { + // First, open a session and generate a nonce. We don't use the nonce in this + // session. + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s2)); + ASSERT_NO_FATAL_FAILURE(s2.GenerateNonce()); + uint32_t nonce = s2.nonce(); + + // Do not use the nonce. Also, leave the session open. We want to make sure + // that session_ and s2 do NOT share a nonce. This is different from + // the LoadKeyNonceReopenSession in that we do not close s1. + + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_request().nonce = nonce; + for (unsigned int i = 0; i < license_messages_.num_keys(); i++) + license_messages_.response_data().keys[i].control.nonce = htonl(nonce); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); +} + +// LoadKeys should fail if the key control block as a bad verification string. +TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadVerification) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.response_data().keys[1].control.verification[2] = 'Z'; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +// This test verifies that LoadKeys still works when the message is not aligned +// in memory on a word (2 or 4 byte) boundary. +TEST_P(OEMCryptoLicenseTest, LoadKeyUnalignedMessageAPI16) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + + std::vector buffer(1, '0'); // A string of 1 byte long. + size_t offset = buffer.size(); + ASSERT_EQ(1u, offset); + // We assume that vectors are allocated on as a small chunk of data that is + // aligned on a word boundary. I.e. we assume buffer is word aligned. Next, + // we append the message to buffer after the single padding byte. + buffer.insert(buffer.end(), + license_messages_.encrypted_response_buffer().begin(), + license_messages_.encrypted_response_buffer().end()); + // Thus, buffer[offset] is NOT word aligned. + const uint8_t* unaligned_message = &buffer[offset]; + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadLicense( + session_.session_id(), unaligned_message, + license_messages_.encrypted_response_buffer().size(), + license_messages_.serialized_core_message().size(), + license_messages_.response_signature().data(), + license_messages_.response_signature().size())); +} + +// Verifies that a session can't reload a license without being closed and +// reopened. +TEST_P(OEMCryptoLicenseTest, LoadLicenseAgainFailureAPI16) { + 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()); + ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); +} + +TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + license_messages_.response_signature()[0] ^= 42; + ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + license_messages_.LoadResponse()); +} +// LoadKeys should fail if we try to load keys with no keys. +TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeys) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(0); + license_messages_.set_num_keys(0); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} + +// Like the previous test, except we ask for a nonce first. +TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeyWithNonce) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_num_keys(0); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +} +/// @} + +/// @addtogroup security +/// @{ + +// Following two tests will test huge values for num bytes clear, num bytes +// encrypted, input data length and clear address, clear address_length. +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesClearAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) { + LoadLicense(); + vector key_handle; + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + + size_t input_buffer_size = 1; + vector in_buffer(input_buffer_size); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description.subsamples); + // If Decrypt cenc API does not check for overflow on clear + encrypted + // addition operation. This will result in 1 which will match with input data + // length, which causes validation to pass. + sub_samples[0].num_bytes_clear = 2; + sub_samples[0].num_bytes_encrypted = ~0; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + // Try to decrypt the data + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern)); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeSecureHandleLength) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + // TestDecryptCENCForHugeBufferLengths alloctes huge secure handle + // buffer. + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesClear) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = sub_samples[0].num_bytes_clear + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesEncryptedAPI16) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeSecureBufferOffset) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sample_description->buffers.output_descriptor.buffer.secure.offset = + sample_description->buffers.output_descriptor.buffer.secure + .secure_buffer_length + + 1; + }, + kDecryptCENCSecureBuffer); +} + +// After loading keys, we should be able to query the key control block. If we +// attempt to query a key that has not been loaded, the error should be +// NO_CONTENT_KEY. +TEST_P(OEMCryptoLicenseTest, QueryKeyControl) { + 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()); + + // Note: successful cases are tested in VerifyTestKeys. + KeyControlBlock block; + size_t size = sizeof(block) - 1; + OEMCryptoResult sts = OEMCrypto_QueryKeyControl( + session_.session_id(), license_messages_.response_data().keys[0].key_id, + license_messages_.response_data().keys[0].key_id_length, + reinterpret_cast(&block), &size); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + return; + } + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + const char* key_id = "no_key"; + size = sizeof(block); + ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_QueryKeyControl( + session_.session_id(), reinterpret_cast(key_id), + strlen(key_id), reinterpret_cast(&block), &size)); +} + +// This case tests against the issue where certain 16.4.x SDK versions return a +// clear key control block (KCB) in the license response. An OEMCrypto v17.1+ +// implementation should be able to handle the clear KCB in the 16.4.x response +// and load the license correctly. +TEST_F(OEMCryptoSessionTests, ClearKcbAPI17) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + // Set odk version in the license response to be 16.4 + oemcrypto_core_message::features::CoreMessageFeatures features = {}; + features.maximum_major_version = 16; + features.maximum_minor_version = 4; + constexpr bool kForceClearKcb = true; + ASSERT_NO_FATAL_FAILURE( + license_messages.EncryptAndSignResponseWithCoreMessageFeatures( + features, kForceClearKcb)); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); + + KeyControlBlock block; + size_t size = sizeof(block); + OEMCryptoResult sts = OEMCrypto_QueryKeyControl( + s.session_id(), license_messages.response_data().keys[0].key_id, + license_messages.response_data().keys[0].key_id_length, + reinterpret_cast(&block), &size); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + return; + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); +} + +// If the device says it supports anti-rollback in the hardware, then it should +// accept a key control block with the anti-rollback hardware bit set. +// Otherwise, it should reject that key control block. +TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + license_messages_.set_control(wvoec::kControlRequireAntiRollbackHardware); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + OEMCryptoResult sts = license_messages_.LoadResponse(); + if (OEMCrypto_IsAntiRollbackHwPresent()) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + } else { + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, sts); + } +} + +// This test verifies that OEMCrypto can load the number of keys required for +// the reported resource level. +TEST_P(OEMCryptoLicenseTest, MinimumKeys) { + const size_t num_keys = GetResourceValue(kMaxKeysPerSession); + ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; + license_messages_.set_num_keys(static_cast(num_keys)); + 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()); + + constexpr bool kSelectKeyFirst = true; + for (size_t key_index = 0; key_index < num_keys; key_index++) { + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); + } +} + +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. This maximizes keys per session. +TEST_P(OEMCryptoLicenseTest, MaxTotalKeysPerSession) { + const size_t max_num_keys = GetResourceValue(kMaxKeysPerSession); + TestMaxKeys(this, max_num_keys); +} + +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. This maximizes number of sessions. +TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) { + const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); + const size_t max_sessions = GetResourceValue(kMaxConcurrentSession); + const size_t max_num_keys = max_total_keys / max_sessions + 1; + TestMaxKeys(this, max_num_keys); +} + +// This test verifies that the minimum patch level can be required. The device +// should accept a key control block with the current patch level, and it should +// reject any key control blocks with a future patch level. +TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { + uint8_t patch_level = OEMCrypto_Security_Patch_Level(); + printf(" Current Patch Level: %u.\n", patch_level); + { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_control(patch_level + << wvoec::kControlSecurityPatchLevelShift); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + EXPECT_EQ(global_features.api_version, license_messages.api_version()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); + } + // Reject any future patch levels. + if (patch_level < 0x3F) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_control((patch_level + 1) + << wvoec::kControlSecurityPatchLevelShift); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, license_messages.LoadResponse()); + } + // Accept an old patch level. + if (patch_level > 0) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_control((patch_level - 1) + << wvoec::kControlSecurityPatchLevelShift); + 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()); + } +} + +/// @} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_license_test.h b/oemcrypto/test/oemcrypto_license_test.h new file mode 100644 index 0000000..fd59d15 --- /dev/null +++ b/oemcrypto/test/oemcrypto_license_test.h @@ -0,0 +1,364 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_LICENSE_TEST_ +#define CDM_OEMCRYPTO_LICENSE_TEST_ + +#include + +#include "OEMCryptoCENC.h" +#include "clock.h" +#include "log.h" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_corpus_generator_helper.h" +#include "oemcrypto_resource_test.h" +#include "wvcrc32.h" + +using ::testing::WithParamInterface; + +namespace wvoec { + +// Used for testing oemcrypto APIs with huge buffers. +typedef const std::function oemcrypto_function; +void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, + size_t start_buffer_length, + size_t end_buffer_length, bool check_status); +void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, bool check_status); + +void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session); + +class OEMCryptoSessionTests : public OEMCryptoClientTest { + public: + vector encrypted_usage_header_; + + protected: + OEMCryptoSessionTests() {} + + void SetUp() override { + OEMCryptoClientTest::SetUp(); + EnsureTestROT(); + if (global_features.usage_table) { + CreateUsageTableHeader(); + } + } + + void CreateUsageTableHeader(bool expect_success = true) { + size_t header_buffer_length = 0; + OEMCryptoResult sts = + OEMCrypto_CreateUsageTableHeader(nullptr, &header_buffer_length); + if (expect_success) { + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + } else { + ASSERT_NE(OEMCrypto_SUCCESS, sts); + if (sts != OEMCrypto_ERROR_SHORT_BUFFER) return; + } + encrypted_usage_header_.resize(header_buffer_length); + sts = OEMCrypto_CreateUsageTableHeader(encrypted_usage_header_.data(), + &header_buffer_length); + if (expect_success) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + encrypted_usage_header_.resize(header_buffer_length); + } else { + ASSERT_NE(OEMCrypto_SUCCESS, sts); + } + } + + void TestPrepareLicenseRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + InstallTestDrmKey(&s); + LicenseRoundTrip license_messages(&s); + f(message_length, &license_messages); + OEMCryptoResult result = + license_messages.SignAndCreateRequestWithCustomBufferLengths(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + OEMCryptoResult LoadLicense(Session& s, LicenseRoundTrip& license_messages) { + InstallTestDrmKey(&s); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + return license_messages.LoadResponse(); + } +}; + +class OEMCryptoSessionTestKeyboxTest : public OEMCryptoSessionTests {}; + +// This class is for testing a single license with the default API version +// of 16. +class OEMCryptoLicenseTestAPI16 : public OEMCryptoSessionTests { + public: + OEMCryptoLicenseTestAPI16() + : license_api_version_(kCurrentAPI), license_messages_(&session_) {} + + void SetUp() override { + OEMCryptoSessionTests::SetUp(); + ASSERT_NO_FATAL_FAILURE(session_.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session_)); + } + + void TearDown() override { + ASSERT_NO_FATAL_FAILURE(session_.close()); + OEMCryptoSessionTests::TearDown(); + } + + protected: + Session session_; + uint32_t license_api_version_; + LicenseRoundTrip license_messages_; +}; + +// This class is used to test a license that is from a server with the specified +// version parameter. Up to two versions old. +class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, + public WithParamInterface { + protected: + void SetUp() override { + // The only difference between this class and its parent is that we use a + // different license api: + license_api_version_ = GetParam(); + license_messages_.set_api_version(license_api_version_); + OEMCryptoLicenseTestAPI16::SetUp(); + } + + void LoadLicense() { + license_messages_.SignAndVerifyRequest(); + license_messages_.CreateDefaultResponse(); + license_messages_.EncryptAndSignResponse(); + license_messages_.LoadResponse(); + } + + void TestDecryptCENCForHugeBufferLengths( + const std::function f, + bool check_status) { + LoadLicense(); + auto oemcrypto_function = [&](size_t message_length) { + vector key_handle; + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + + size_t input_buffer_size = 1; + vector in_buffer(input_buffer_size + message_length); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description); + + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description.subsamples); + // Actual tests modifies either of these fields to match clear + encrypted + // = in_buffer.size(). + sub_samples[0].num_bytes_clear = 0; + sub_samples[0].num_bytes_encrypted = input_buffer_size; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + f(message_length, &sample_description); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return sts; + } + } + // Try to decrypt the data + OEMCryptoResult result = + OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(), + &sample_description, 1, &pattern); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCrypto_FreeSecureBuffer( + session_.session_id(), + &sample_description.buffers.output_descriptor, secure_fd); + } + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestDecryptCENCForOutOfRangeOffsetsAndLengths( + const std::function f, + bool update_secure_buffer) { + LoadLicense(); + vector key_handle; + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + if (update_secure_buffer) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return; + } + } + f(&sample_description); + // Try to decrypt the data + OEMCryptoResult result = OEMCrypto_DecryptCENC( + key_handle.data(), key_handle.size(), &sample_description, 1, &pattern); + if (update_secure_buffer) { + OEMCrypto_FreeSecureBuffer(session_.session_id(), + &sample_description.buffers.output_descriptor, + secure_fd); + } + ASSERT_NE(OEMCrypto_SUCCESS, result); + } +}; + +// Test usage table functionality. +class LicenseWithUsageEntry { + public: + LicenseWithUsageEntry(const std::string& pst = "my_pst") + : session_(), + license_messages_(&session_), + generic_crypto_(false), + time_license_received_(0), + time_first_decrypt_(0), + time_last_decrypt_(0), + active_(true) { + license_messages_.set_pst(pst); + } + + void MakeAndLoadOnline(OEMCryptoSessionTests* test) { + MakeAndLoad(test, + wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired); + } + + // If status in not a nullptr, then creating a new entry is allowed to fail, + // and its error code is stored in status. + void MakeOfflineAndClose(OEMCryptoSessionTests* test, + OEMCryptoResult* status = nullptr) { + MakeAndLoad(test, wvoec::kControlNonceOrEntry, status); + if (status != nullptr && *status != OEMCrypto_SUCCESS) { + ASSERT_NO_FATAL_FAILURE(session_.close()); + return; + } + ASSERT_NO_FATAL_FAILURE( + session_.UpdateUsageEntry(&(test->encrypted_usage_header_))); + ASSERT_NO_FATAL_FAILURE(GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(session_.close()); + } + + // If status in not a nullptr, then creating a new entry is allowed to fail, + // and its error code is stored in status. + void MakeAndLoad(SessionUtil* util, uint32_t control, + OEMCryptoResult* status = nullptr) { + license_messages_.set_control(control); + ASSERT_NO_FATAL_FAILURE(session_.open()); + ASSERT_NO_FATAL_FAILURE(util->InstallTestDrmKey(&session_)); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + if (generic_crypto_) { + ASSERT_NO_FATAL_FAILURE( + license_messages_.CreateResponseWithGenericCryptoKeys()); + } else { + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + } + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry(status)); + if (status != nullptr && *status != OEMCrypto_SUCCESS) return; + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + time_license_received_ = wvutil::Clock().GetCurrentTime(); + } + + void OpenAndReload(SessionUtil* util) { + ASSERT_NO_FATAL_FAILURE(session_.open()); + ASSERT_NO_FATAL_FAILURE(session_.ReloadUsageEntry()); + ASSERT_NO_FATAL_FAILURE(util->InstallTestDrmKey(&session_)); + ASSERT_NO_FATAL_FAILURE(session_.GenerateDerivedKeysFromSessionKey()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + } + + // Test decrypt, and update the decrypt times for the pst report. + void TestDecryptCTR(bool select_key_first = true, + OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { + session_.TestDecryptCTR(select_key_first, expected_result); + time_last_decrypt_ = wvutil::Clock().GetCurrentTime(); + if (time_first_decrypt_ == 0) time_first_decrypt_ = time_last_decrypt_; + } + + void DeactivateUsageEntry() { + active_ = false; + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_deactivate_usage_entry_fuzz_seed_corpus"); + AppendToFile(file_name, pst().c_str(), pst().length()); + } + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_DeactivateUsageEntry( + session_.session_id(), + reinterpret_cast(pst().c_str()), pst().length())); + } + + void GenerateVerifyReport(OEMCrypto_Usage_Entry_Status status) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateReport(pst())); + Test_PST_Report expected(pst(), status); + ASSERT_NO_FATAL_FAILURE( + session_.VerifyReport(expected, time_license_received_, + time_first_decrypt_, time_last_decrypt_)); + // The PST report was signed above. Below we verify that the entire message + // that is sent to the server will be signed by the right mac keys. + RenewalRoundTrip renewal_messages(&license_messages_); + renewal_messages.set_is_release(!active_); + ASSERT_NO_FATAL_FAILURE(renewal_messages.SignAndVerifyRequest()); + } + + void ReloadUsageEntry() { + session_.ReloadUsageEntry(); + session_.set_mac_keys(license_messages_.response_data().mac_keys); + } + + const std::string& pst() const { return license_messages_.pst(); } + void set_pst(const std::string& pst) { license_messages_.set_pst(pst); } + LicenseRoundTrip& license_messages() { return license_messages_; } + Session& session() { return session_; } + void set_generic_crypto(bool generic_crypto) { + generic_crypto_ = generic_crypto; + } + + private: + Session session_; + LicenseRoundTrip license_messages_; + bool generic_crypto_; + int64_t time_license_received_; + int64_t time_first_decrypt_; + int64_t time_last_decrypt_; + bool active_; +}; + +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_LICENSE_TEST_ \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_provisioning_test.cpp b/oemcrypto/test/oemcrypto_provisioning_test.cpp new file mode 100644 index 0000000..ea687ee --- /dev/null +++ b/oemcrypto/test/oemcrypto_provisioning_test.cpp @@ -0,0 +1,869 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "oemcrypto_provisioning_test.h" + +#include "log.h" +#include "platform.h" + +namespace wvoec { + +/// @addtogroup provision +/// @{ + +// This test is used to print the device ID to stdout. +TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { + OEMCryptoResult sts; + uint8_t dev_id[128] = {0}; + size_t dev_id_len = 128; + sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + cout << " NormalGetDeviceId: dev_id = " + << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; +} + +TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) { + OEMCryptoResult sts; + uint8_t dev_id[128]; + for (int i = 0; i < 128; ++i) { + dev_id[i] = 0x55; + } + dev_id[127] = '\0'; + size_t dev_id_len = 0; + sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + // On short buffer error, function should return minimum buffer length + ASSERT_GT(dev_id_len, 0u); + // Should also return short buffer if passed a zero length and a null buffer. + dev_id_len = 0; + sts = OEMCrypto_GetDeviceID(nullptr, &dev_id_len); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + // On short buffer error, function should return minimum buffer length + ASSERT_GT(dev_id_len, 0u); +} + +TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { + OEMCryptoResult sts; + uint8_t key_data[256]; + size_t key_data_len = sizeof(key_data); + sts = OEMCrypto_GetKeyData(key_data, &key_data_len); + + uint32_t* data = reinterpret_cast(key_data); + printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n", + htonl(data[1]), htonl(data[1]), htonl(data[0])); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); +} + +TEST_F(OEMCryptoKeyboxTest, GetKeyDataNullPointer) { + OEMCryptoResult sts; + uint8_t key_data[256]; + sts = OEMCrypto_GetKeyData(key_data, nullptr); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + +// This test makes sure the installed keybox is valid. It doesn't really check +// that it is a production keybox. That must be done by an integration test. +TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); +} + +// This tests GenerateDerivedKeys with an 8k context. +TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + const size_t max_size = GetResourceValue(kLargeMessageSize); + vector mac_context(max_size); + vector enc_context(max_size); + // Stripe the data so the two vectors are not identical, and not all zeroes. + for (size_t i = 0; i < max_size; i++) { + mac_context[i] = i % 0x100; + enc_context[i] = (3 * i) % 0x100; + } + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GenerateDerivedKeys( + s.session_id(), mac_context.data(), mac_context.size(), + enc_context.data(), enc_context.size())); +} + +// This verifies that the device really does claim to have a certificate. +// It should be filtered out for devices that have a keybox. +TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) { + ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); +} + +TEST_F(OEMCryptoProv30Test, GetDeviceId) { + OEMCryptoResult sts; + std::vector dev_id(128, 0); + size_t dev_id_len = dev_id.size(); + sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + ASSERT_GT(dev_id_len, 0u); + dev_id.resize(dev_id_len); + sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + dev_id.resize(dev_id_len); + cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) + << " len = " << dev_id_len << endl; +} + +// The OEM certificate must be valid. +TEST_F(OEMCryptoProv30Test, CertValidAPI15) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxOrOEMCertValid()); +} + +TEST_F(OEMCryptoProv30Test, OEMCertValid) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + bool kVerify = true; + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert(kVerify)); // Load and verify. +} + +// This verifies that the OEM Certificate cannot be used for other RSA padding +// schemes. Those schemes should only be used by cast receiver certificates. +TEST_F(OEMCryptoProv30Test, OEMCertForbiddenPaddingScheme) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + OEMCryptoResult sts; + // Sign a Message + vector data(500); + GetRandBytes(data.data(), data.size()); + size_t signature_length = 0; + // We need a size one vector to pass as a pointer. + vector signature(1, 0); + vector zero(1, 0); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), data.size(), + signature.data(), &signature_length, + kSign_PKCS1_Block1); + if (OEMCrypto_ERROR_SHORT_BUFFER == sts) { + // The OEMCrypto could complain about buffer length first, so let's + // resize and check if it's writing to the signature again. + signature.resize(signature_length, 0); + zero.resize(signature_length, 0); + sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), + data.size(), signature.data(), + &signature_length, kSign_PKCS1_Block1); + } + EXPECT_NE(OEMCrypto_SUCCESS, sts) + << "OEM Cert Signed with forbidden kSign_PKCS1_Block1."; + ASSERT_EQ(zero, signature); // signature should not be computed. +} + +// Calling OEMCrypto_GetOEMPublicCertificate should not change the session's +// private key. +TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) { + 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()); + } + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // Install the DRM Cert's RSA key. + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); + ASSERT_NO_FATAL_FAILURE(s.SetTestRsaPublicKey()); + // Request the OEM Cert. -- This should NOT load the OEM Private key. + vector public_cert; + size_t public_cert_length = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_GetOEMPublicCertificate(nullptr, &public_cert_length)); + ASSERT_LT(0u, public_cert_length); + public_cert.resize(public_cert_length); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetOEMPublicCertificate( + public_cert.data(), &public_cert_length)); + // Derive keys from the session key -- this should use the DRM Cert's key. + // It should NOT use the OEM Private key because that key should not have + // been loaded. + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey()); + // Now fill a message and try to load it. + LicenseRoundTrip license_messages(&s); + license_messages.set_control(0); + 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()); +} + +// This verifies that the device really does claim to have BCC. +// It should be filtered out for devices that have a keybox or factory OEM +// cert. +TEST_F(OEMCryptoProv40Test, DeviceClaimsBootCertificateChain) { + ASSERT_EQ(OEMCrypto_GetProvisioningMethod(), OEMCrypto_BootCertificateChain); +} + +// Verifies that short buffer error returns when the buffer is short. +TEST_F(OEMCryptoProv40Test, GetBootCertificateChainShortBuffer) { + 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); + ASSERT_NE(bcc_size, 0uL); +} + +// Verifies BCC can be successfully returned. +TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) { + 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); +} + +// Verifies that short buffer error returns when the buffer is short. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairShortBuffer) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + std::vector public_key; + size_t public_key_size = 0; + std::vector public_key_signature; + size_t public_key_signature_size = 0; + std::vector wrapped_private_key; + size_t wrapped_private_key_size = 0; + OEMCrypto_PrivateKeyType key_type; + + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_ERROR_SHORT_BUFFER); + + ASSERT_NE(public_key_size, 0uL); + ASSERT_NE(public_key_signature_size, 0uL); + ASSERT_NE(wrapped_private_key_size, 0uL); +} + +// Verifies a pair of key can be successfully returned. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairSuccess) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + std::vector public_key; + size_t public_key_size = 0; + std::vector public_key_signature; + size_t public_key_signature_size = 0; + std::vector wrapped_private_key; + size_t wrapped_private_key_size = 0; + OEMCrypto_PrivateKeyType key_type; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_ERROR_SHORT_BUFFER); + public_key.resize(public_key_size); + public_key_signature.resize(public_key_signature_size); + wrapped_private_key.resize(wrapped_private_key_size); + + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_SUCCESS); + public_key.resize(public_key_size); + public_key_signature.resize(public_key_signature_size); + wrapped_private_key.resize(wrapped_private_key_size); + // Parse the public key generated to make sure it is correctly formatted. + ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey( + key_type, public_key.data(), public_key_size)); +} + +// Verifies the generated key pairs are different on each call. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairsAreDifferent) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // Large buffer to make sure it is large enough. + size_t public_key_size1 = 10000; + std::vector public_key1(public_key_size1); + size_t public_key_signature_size1 = 10000; + std::vector public_key_signature1(public_key_signature_size1); + size_t wrapped_private_key_size1 = 10000; + std::vector wrapped_private_key1(wrapped_private_key_size1); + OEMCrypto_PrivateKeyType key_type1; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key1.data(), &public_key_size1, + public_key_signature1.data(), &public_key_signature_size1, + wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size1, 0UL); + EXPECT_NE(public_key_signature_size1, 0UL); + EXPECT_NE(wrapped_private_key_size1, 0UL); + public_key1.resize(public_key_size1); + public_key_signature1.resize(public_key_signature_size1); + wrapped_private_key1.resize(wrapped_private_key_size1); + + size_t public_key_size2 = 10000; + std::vector public_key2(public_key_size2); + size_t public_key_signature_size2 = 10000; + std::vector public_key_signature2(public_key_signature_size2); + size_t wrapped_private_key_size2 = 10000; + std::vector wrapped_private_key2(wrapped_private_key_size2); + OEMCrypto_PrivateKeyType key_type2; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key2.data(), &public_key_size2, + public_key_signature2.data(), &public_key_signature_size2, + wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size2, 0UL); + EXPECT_NE(public_key_signature_size2, 0UL); + EXPECT_NE(wrapped_private_key_size2, 0UL); + public_key2.resize(public_key_size2); + public_key_signature2.resize(public_key_signature_size2); + wrapped_private_key2.resize(wrapped_private_key_size2); + + EXPECT_NE(public_key1, public_key2); + EXPECT_NE(public_key_signature1, public_key_signature2); + EXPECT_NE(wrapped_private_key1, wrapped_private_key2); +} + +TEST_F(OEMCryptoProv40Test, GetDeviceInformationAPI18) { + std::vector device_info; + size_t device_info_length = 0; + OEMCryptoResult sts = + OEMCrypto_GetDeviceInformation(device_info.data(), &device_info_length); + ASSERT_EQ(sts, OEMCrypto_ERROR_SHORT_BUFFER); + ASSERT_NE(device_info_length, 0uL); + device_info.resize(device_info_length); + ASSERT_EQ( + OEMCrypto_GetDeviceInformation(device_info.data(), &device_info_length), + OEMCrypto_SUCCESS); + EXPECT_NE(device_info_length, 0uL); +} + +TEST_F(OEMCryptoProv40Test, GetDeviceSignedCsrPayloadAPI18) { + std::vector challenge(64, 0xaa); + // TODO: add cppbor support for oemcrypto tests for all targets. Before that, + // use hex values which are equivalent of the commented cppbor statement. + // std::vector device_info = cppbor::Map() + // .add("manufacturer", "google") + // .add("fused", 0) + // .add("other", "ignored") + // .canonicalize() + // .encode(); + // + std::vector device_info = { + 0xa3, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x0, 0x65, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x67, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, + 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x72, 0x66, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65}; + std::vector signed_csr_payload; + size_t signed_csr_payload_length = 0; + OEMCryptoResult sts = OEMCrypto_GetDeviceSignedCsrPayload( + challenge.data(), challenge.size(), device_info.data(), + device_info.size(), signed_csr_payload.data(), + &signed_csr_payload_length); + ASSERT_EQ(sts, OEMCrypto_ERROR_SHORT_BUFFER); + ASSERT_NE(signed_csr_payload_length, 0uL); + signed_csr_payload.resize(signed_csr_payload_length); + ASSERT_EQ(OEMCrypto_GetDeviceSignedCsrPayload( + challenge.data(), challenge.size(), device_info.data(), + device_info.size(), signed_csr_payload.data(), + &signed_csr_payload_length), + OEMCrypto_SUCCESS); + EXPECT_NE(signed_csr_payload_length, 0uL); +} + +TEST_F(OEMCryptoProv40Test, GetDeviceSignedCsrPayloadInvalid) { + std::vector signed_csr_payload; + size_t signed_csr_payload_length = 0; + std::vector challenge(64, 0xaa); + std::vector device_info = { + 0xa3, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x0, 0x65, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x67, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, + 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x72, 0x66, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65}; + std::vector challenge_empty; + OEMCryptoResult sts = OEMCrypto_GetDeviceSignedCsrPayload( + challenge_empty.data(), challenge_empty.size(), device_info.data(), + device_info.size(), signed_csr_payload.data(), + &signed_csr_payload_length); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) return; + ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT); + + // Oversized challenge + std::vector challenge_long(65, 0xaa); + sts = OEMCrypto_GetDeviceSignedCsrPayload( + challenge_long.data(), challenge_long.size(), device_info.data(), + device_info.size(), signed_csr_payload.data(), + &signed_csr_payload_length); + ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT); + + std::vector device_empty; + sts = OEMCrypto_GetDeviceSignedCsrPayload( + challenge.data(), challenge.size(), device_empty.data(), + device_empty.size(), signed_csr_payload.data(), + &signed_csr_payload_length); + ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT); +} + +// Verifies that an OEM private key can be installed. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeySuccess) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // First generate a key pair. + // Large buffer to make sure it is large enough. + size_t public_key_size = 10000; + std::vector public_key(public_key_size); + size_t public_key_signature_size = 10000; + std::vector public_key_signature(public_key_signature_size); + size_t wrapped_private_key_size = 10000; + std::vector wrapped_private_key(wrapped_private_key_size); + OEMCrypto_PrivateKeyType key_type; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_SUCCESS); + public_key.resize(public_key_size); + public_key_signature.resize(public_key_signature_size); + wrapped_private_key.resize(wrapped_private_key_size); + + // Install the generated private key. + ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key_size), + OEMCrypto_SUCCESS); +} + +// If data is empty or random, the API should return non-success status. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyInvalidDataFail) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + + // Empty key fails. + std::vector wrapped_private_key; + OEMCrypto_PrivateKeyType key_type = OEMCrypto_RSA_Private_Key; + ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key.size()), + OEMCrypto_SUCCESS); + + // Random key data fails. + wrapped_private_key = {1, 2, 3}; + ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key.size()), + OEMCrypto_SUCCESS); +} + +// Verifies that an OEM private key can be installed, and used by +// GenerateCertificateKeyPair call. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // First generate a key pair. + size_t public_key_size1 = 10000; + std::vector public_key1(public_key_size1); + size_t public_key_signature_size1 = 10000; + std::vector public_key_signature1(public_key_signature_size1); + size_t wrapped_private_key_size1 = 10000; + std::vector wrapped_private_key1(wrapped_private_key_size1); + OEMCrypto_PrivateKeyType key_type1; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key1.data(), &public_key_size1, + public_key_signature1.data(), &public_key_signature_size1, + wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size1, 0UL); + EXPECT_NE(public_key_signature_size1, 0UL); + EXPECT_NE(wrapped_private_key_size1, 0UL); + public_key1.resize(public_key_size1); + public_key_signature1.resize(public_key_signature_size1); + wrapped_private_key1.resize(wrapped_private_key_size1); + + // Install the generated private key. + ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type1, + wrapped_private_key1.data(), + wrapped_private_key_size1), + OEMCrypto_SUCCESS); + + // Now calling GenerateCertificateKeyPair should use wrapped_private_key to + // sign the newly generated public key. + size_t public_key_size2 = 10000; + std::vector public_key2(public_key_size2); + size_t public_key_signature_size2 = 10000; + std::vector public_key_signature2(public_key_signature_size2); + size_t wrapped_private_key_size2 = 10000; + std::vector wrapped_private_key2(wrapped_private_key_size2); + OEMCrypto_PrivateKeyType key_type2; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key2.data(), &public_key_size2, + public_key_signature2.data(), &public_key_signature_size2, + wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size2, 0UL); + EXPECT_NE(public_key_signature_size2, 0UL); + EXPECT_NE(wrapped_private_key_size2, 0UL); + public_key2.resize(public_key_size2); + public_key_signature2.resize(public_key_signature_size2); + wrapped_private_key2.resize(wrapped_private_key_size2); + + // Verify public_key_signature2 with public_key1. + if (key_type2 == 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) { + ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey( + public_key1.data(), public_key1.size())); + ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2, + public_key_signature2.data(), + public_key_signature2.size())); + } +} + +/** Verify that the private key from an OEM Cert cannot be loaded as a DRM + * cert. + */ +TEST_F(OEMCryptoProv40Test, OEMPrivateKeyCannotBeDRMKey) { + // Create an OEM Cert and save it for alter. + Session s1; + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s1)); + ASSERT_EQ(s1.IsPublicKeySet(), true); + s1.close(); + const std::vector wrapped_oem_key1 = wrapped_oem_key_; + // Now create a new OEM cert, load the second key, and try to load key1 + // as the DRM key. + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s2)); + s2.close(); + // Load the current key as the OEM key in session 3. + Session s3; + ASSERT_NO_FATAL_FAILURE(s3.open()); + // Now try to load key 1 as a DRM key. That should fail. + ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY, + OEMCrypto_LoadDRMPrivateKey(s3.session_id(), oem_key_type_, + wrapped_oem_key1.data(), + wrapped_oem_key1.size())); +} + +/** The private key for a DRM Cert cannot be loaded as an OEM Certificate. */ +TEST_F(OEMCryptoProv40Test, DRMPrivateKeyCannotBeOEMKey) { + // Create a DRM cert and save it for later. + Session s1; + // Make sure the drm private key exists. + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s1)); + ASSERT_NE(wrapped_drm_key_.size(), 0u); + // Now try to load the drm private key as an OEM key. + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY, + OEMCrypto_InstallOemPrivateKey( + s2.session_id(), drm_key_type_, + reinterpret_cast(wrapped_drm_key_.data()), + wrapped_drm_key_.size())); +} + +TEST_F(OEMCryptoProv40Test, GetDeviceId) { + OEMCryptoResult sts; + std::vector dev_id; + size_t dev_id_len = dev_id.size(); + sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + ASSERT_GT(dev_id_len, 0u); + dev_id.resize(dev_id_len); + sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + dev_id.resize(dev_id_len); + cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) + << " len = " << dev_id_len << endl; + // Device id should be stable. Query again. + std::vector dev_id2(dev_id_len); + sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(dev_id2, dev_id); +} + +// Verifies provisioning stage 1 OEM cert provisioning round trip works +TEST_F(OEMCryptoProv40Test, ProvisionOemCert) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s)); + ASSERT_EQ(s.IsPublicKeySet(), true); +} + +// Verifies both provisioning stages OEM and DRM cert provisioning round trip +// works +TEST_F(OEMCryptoProv40Test, ProvisionDrmCert) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_EQ(s.IsPublicKeySet(), true); +} + +TEST_F(OEMCryptoLoadsCertificate, PrepAndSignLicenseRequestCounterAPI18) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); + s.GenerateNonce(); + + size_t core_message_length = 100; + std::vector message(128, 0); + std::vector signature(256, 0); + size_t signature_length = signature.size(); + + OEMCryptoResult result = OEMCrypto_PrepAndSignLicenseRequest( + s.session_id(), message.data(), message.size(), &core_message_length, + signature.data(), &signature_length); + + ASSERT_EQ(OEMCrypto_SUCCESS, result); +} + +// This test verifies that we can create a wrapped RSA key, and then reload it. +TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); +} + +TEST_F(OEMCryptoLoadsCertificate, SignProvisioningRequest) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { + s.LoadOEMCert(true); + } else { + EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox); + s.GenerateDerivedKeysFromKeybox(keybox_); + } + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); +} + +// This tests a large message size. The size is larger than we required in v15. +TEST_F(OEMCryptoLoadsCertificate, SignLargeProvisioningRequestAPI16) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { + s.LoadOEMCert(true); + } else { + EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox); + s.GenerateDerivedKeysFromKeybox(keybox_); + } + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + const size_t max_size = GetResourceValue(kLargeMessageSize); + provisioning_messages.set_message_size(max_size); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); +} + +// This creates a wrapped RSA key, and then does the sanity check that the +// unencrypted key is not found in the wrapped key. The wrapped key should be +// encrypted. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + // We should not be able to find the rsa key in the wrapped key. It should + // be encrypted. + EXPECT_EQ(nullptr, find(provisioning_messages.wrapped_rsa_key(), + provisioning_messages.encoded_rsa_key())); +} + +// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning +// message. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + // Encrypt and sign once, so that we can use the size of the response. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + provisioning_messages.core_response().enc_private_key.offset = + provisioning_messages.encrypted_response_buffer().size() + 1; + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning +// message. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + // Encrypt and sign once, so that we can use the size of the response. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + provisioning_messages.core_response().enc_private_key_iv.offset = + provisioning_messages.encrypted_response_buffer().size() + 1; + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning +// message. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + // Encrypt and sign once, so that we can use the size of the response. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + // If the offset is before the end, but the offset+length is bigger, then + // the message should be rejected. + provisioning_messages.core_response().enc_private_key.offset = + provisioning_messages.encrypted_response_buffer().size() - 5; + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning +// message. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange4_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + // Encrypt and sign once, so that we can use the size of the response. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + // If the offset is before the end, but the offset+length is bigger, then + // the message should be rejected. + provisioning_messages.core_response().enc_private_key_iv.offset = + provisioning_messages.encrypted_response_buffer().size() - 5; + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning +// message. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange5Prov30_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + // Encrypt and sign once, so that we can use the size of the response. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + // If the offset is before the end, but the offset+length is bigger, then + // the message should be rejected. + provisioning_messages.core_response().encrypted_message_key.offset = + provisioning_messages.encrypted_response_buffer().size() + 1; + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Test that RewrapDeviceRSAKey verifies the message signature. +// TODO(b/144186970): This test should also run on Prov 3.0 devices. +TEST_F(OEMCryptoLoadsCertificate, + CertificateProvisionBadSignatureKeyboxTestAPI16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + provisioning_messages.response_signature()[4] ^= 42; // bad signature. + ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Test that RewrapDeviceRSAKey verifies the nonce is current. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce_API16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + provisioning_messages.core_request().nonce ^= 42; // bad nonce. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, + provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Test that RewrapDeviceRSAKey verifies the RSA key is valid. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + provisioning_messages.response_data().rsa_key[4] ^= 42; // bad key. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Test that RewrapDeviceRSAKey verifies the RSA key is valid. +// TODO(b/144186970): This test should also run on Prov 3.0 devices. +TEST_F(OEMCryptoLoadsCertificate, + CertificateProvisionBadRSAKeyKeyboxTestAPI16) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + size_t rsa_offset = + provisioning_messages.core_response().enc_private_key.offset; + // Offsets are relative to the message body, after the core message. + rsa_offset += provisioning_messages.serialized_core_message().size(); + rsa_offset += 4; // Change the middle of the key. + provisioning_messages.encrypted_response_buffer()[rsa_offset] ^= 42; + ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + provisioning_messages.LoadResponse()); + provisioning_messages.VerifyLoadFailed(); +} + +// Test that RewrapDeviceRSAKey accepts the maximum message size. +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + const size_t max_size = GetResourceValue(kLargeMessageSize); + provisioning_messages.set_message_size(max_size); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + // We should not be able to find the rsa key in the wrapped key. It should + // be encrypted. + EXPECT_EQ(nullptr, find(provisioning_messages.wrapped_rsa_key(), + provisioning_messages.encoded_rsa_key())); +} + +/// @} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_provisioning_test.h b/oemcrypto/test/oemcrypto_provisioning_test.h new file mode 100644 index 0000000..2233842 --- /dev/null +++ b/oemcrypto/test/oemcrypto_provisioning_test.h @@ -0,0 +1,116 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_PROVISIONING_TEST_ +#define CDM_OEMCRYPTO_PROVISIONING_TEST_ + +#include + +#include "OEMCryptoCENC.h" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_license_test.h" +#include "oemcrypto_resource_test.h" + +namespace wvoec { + +// Tests using this class are only used for devices with a keybox. They are not +// run for devices with an OEM Certificate. +class OEMCryptoKeyboxTest : public OEMCryptoClientTest { + void SetUp() override { + OEMCryptoClientTest::SetUp(); + OEMCryptoResult sts = OEMCrypto_IsKeyboxValid(); + // If the production keybox is valid, use it for these tests. Most of the + // other tests will use a test keybox anyway, but it's nice to check the + // device ID for the real keybox if we can. + if (sts == OEMCrypto_SUCCESS) return; + printf("Production keybox is NOT valid. All tests use test keybox.\n"); + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_LoadTestKeybox(reinterpret_cast(&kTestKeybox), + sizeof(kTestKeybox))); + } +}; + +// This class is for tests that have an OEM Certificate instead of a keybox. +class OEMCryptoProv30Test : public OEMCryptoClientTest {}; + +// This class is for tests that have boot certificate chain instead of a keybox. +class OEMCryptoProv40Test : public OEMCryptoClientTest {}; + +// +// Certificate Root of Trust Tests +// +class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest { + protected: + void TestPrepareProvisioningRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { + s.LoadOEMCert(true); + } else { + s.GenerateDerivedKeysFromKeybox(keybox_); + } + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + f(message_length, &provisioning_messages); + return provisioning_messages + .SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForHugeBufferLengths( + const std::function f, + bool check_status, bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make provisioning message big enough so that updated core message + // substring offset and length values from tests are still able to read + // valid data from provisioning_message buffer rather than some garbage + // data. + provisioning_messages.set_message_size( + sizeof(provisioning_messages.response_data()) + message_length); + } + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + const std::function f) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + size_t message_length = sizeof(provisioning_messages.response_data()); + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_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); + } +}; + +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_PROVISIONING_TEST_ \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_resource_test.h b/oemcrypto/test/oemcrypto_resource_test.h new file mode 100644 index 0000000..9a5c0b0 --- /dev/null +++ b/oemcrypto/test/oemcrypto_resource_test.h @@ -0,0 +1,62 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_RESOURCE_TEST_ +#define CDM_OEMCRYPTO_RESOURCE_TEST_ + +#include + +#include "OEMCryptoCENC.h" +#include "oemcrypto_types.h" + +namespace wvoec { +constexpr size_t kBufferOverrunPadding = 16; + +// Resource tiers: +constexpr size_t KiB = 1024; +constexpr size_t MiB = 1024 * 1024; +// Huge input buffer length used for OEMCryptoMemory* tests. +constexpr size_t kHugeInputBufferLength = 100 * MiB; +constexpr bool kCheckStatus = true; +constexpr bool kUpdateCoreMessageSubstringValues = true; +constexpr bool kDecryptCENCSecureBuffer = true; +constexpr size_t kHugeRandomNumber = 541236; +// With OEMCrypto v15 and above, we have different resource requirements +// depending on the resource rating reported by OEMCrypto. This function looks +// up the required value for the specified resource for the target OEMCrypto +// library. +template +T GetResourceValue(T (&resource_values)[N]) { + if (global_features.resource_rating < 1) return resource_values[0]; + if (global_features.resource_rating > N) return resource_values[N - 1]; + return resource_values[global_features.resource_rating - 1]; +} + +// After API 16, we require 300 entries in the usage table. Before API 16, we +// required 200. +inline size_t RequiredUsageSize() { + return global_features.api_version < 16 ? 200 : 300; +} + +// These are the maximum sizes we test. That means it is the minimum size that +// OEMCrypto must support. +// clang-format off +const size_t kMaxSampleSize[] = { 1*MiB, 2*MiB, 4*MiB, 16*MiB}; +const size_t kMaxNumberSubsamples[] = { 10, 16, 32, 64}; +const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB, 4*MiB}; +const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB, 1*MiB}; +const size_t kMaxConcurrentSession[] = { 10, 20, 30, 40}; +const size_t kMaxKeysPerSession[] = { 4, 20, 20, 30}; +const size_t kMaxTotalKeys[] = { 16, 40, 80, 90}; +const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; +const size_t kMaxTotalDRMPrivateKeys[] = { 2, 4, 6, 8}; +// Note: Frame rate and simultaneous playback are specified by resource rating, +// but are tested at the system level, so there are no unit tests for frame +// rate. Similarly, number of subsamples for AV1 +// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576}; +// clang-format on +} // namespace wvoec +#endif // CDM_OEMCRYPTO_RESOURCE_TEST_ diff --git a/oemcrypto/test/oemcrypto_security_test.cpp b/oemcrypto/test/oemcrypto_security_test.cpp new file mode 100644 index 0000000..dc39198 --- /dev/null +++ b/oemcrypto/test/oemcrypto_security_test.cpp @@ -0,0 +1,1186 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO(b/253779846) Change it to include a header instead +#include "oemcrypto_test.cpp" + +using ::testing::Bool; +using ::testing::Combine; +using ::testing::Range; +using ::testing::tuple; +using ::testing::Values; +using ::testing::WithParamInterface; +using namespace std; + +namespace wvoec { + +/// @addtogroup security +/// @{ + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryAllocateSecureBufferForHugeBufferSize) { + Session s; + s.open(); + auto oemcrypto_function = [&s](size_t buffer_size) { + OEMCrypto_DestBufferDesc output_descriptor; + int secure_fd; + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + s.session_id(), buffer_size, &output_descriptor, &secure_fd); + if (sts == OEMCrypto_SUCCESS) { + OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, secure_fd); + } + return sts; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLength) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + memcpy(keybox_buffer.data(), &kTestKeybox, sizeof(kTestKeybox)); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, sizeof(kTestKeybox), + kHugeInputBufferLength, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeWrappedKeyboxLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t wrapped_keybox_length = buffer_length; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + // API expects keybox length and wrapped keybox length to be equal. We would + // like to test for various values of wrapped keybox lengths, hence skipping + // status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { + auto oemcrypto_function = [](size_t transport_key_length) { + 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( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F( + OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLengthStartingFromLength1) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + // Cannot check status as keybox will not be valid for this test. + // We still want to test what happens if buffer lengths is less that keybox + // length. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +// Test that set sandbox doesn't crash for a large sandbox id leangth. +TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForHugeSandboxIdLength) { + auto oemcrypto_function = [](size_t buffer_length) { + vector buffer(buffer_length); + return OEMCrypto_SetSandbox(buffer.data(), buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForHugeBufferLengths) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; + + auto oemcrypto_function = [&s, &dest_buffer_descriptor, + &input_buffer](size_t buffer_length) { + input_buffer.resize(buffer_length); + int secure_fd; + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + s.session_id(), buffer_length, &dest_buffer_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return sts; + } + + dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; + OEMCryptoResult status = OEMCrypto_CopyBuffer( + s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); + OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, + secure_fd); + return status; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryCopyBufferDirectForHugeBufferLengths) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Direct; + dest_buffer_descriptor.buffer.direct.is_video = false; + + auto oemcrypto_function = [&s, &dest_buffer_descriptor, + &input_buffer](size_t buffer_length) { + input_buffer.resize(buffer_length); + OEMCryptoResult status = OEMCrypto_CopyBuffer( + s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); + return status; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForOutOfRangeOffset) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; + + size_t buffer_length = KiB; + input_buffer.resize(buffer_length); + int secure_fd; + if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length, + &dest_buffer_descriptor, + &secure_fd) != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return; + } + + dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; + auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer, + &buffer_length](size_t offset) { + dest_buffer_descriptor.buffer.secure.offset = offset; + return OEMCrypto_CopyBuffer( + s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, + secure_fd); +} + +/******** Dangerous Tests - DO NOT RUN ***********/ +/*The following tests try to test InstallKeybox API with random buffers of +varying length in order to catch any overflow issues. These tests override the +actual keybox on the device. Remove the if and endif statement to run these +tests on a device ONLY IF YOU ARE ABLE TO RECOVER THE KEYBOX on the device.*/ +#if 0 +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox)); + return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); + }; + // Starting at sizeof(kTestKeybox) as we are copying valid keybox + // at beginning of generated buffers. + TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength, + kCheckStatus); +} + +TEST_F(OEMCryptoKeyboxTest, + OEMCryptoMemoryInstallKeyboxForHugeKeyboxBufferStartingFromLength1) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); + }; + // We are testing for keybox lengths starting from 1 which would return error, + // hence skipping status check. + TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); +} +#endif + +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox)); + return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); + }; + // Starting at sizeof(kTestKeybox) as we are copying valid keybox + // at beginning of generated buffers. + TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength, + kCheckStatus); +} + +TEST_F(OEMCryptoKeyboxTest, + OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBufferStartingFromLength1) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); + }; + // We are testing for keybox lengths starting from 1 which would return error, + // hence skipping status check. + TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); +} + +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetDeviceIdForHugeIdLength) { + auto oemcrypto_function = [](size_t input_length) { + size_t device_id_length = input_length; + vector device_id(device_id_length); + return OEMCrypto_GetDeviceID(device_id.data(), &device_id_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForHugeIdLength) { + auto oemcrypto_function = [](size_t input_length) { + size_t key_data_length = input_length; + vector key_data(key_data_length); + return OEMCrypto_GetKeyData(key_data.data(), &key_data_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +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_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_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { + if (wrapped_rsa_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()); + } + 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.SetTestRsaPublicKey()); + + auto oemcrypto_function = [](size_t input_length) { + size_t public_cert_length = input_length; + vector public_cert(public_cert_length); + return OEMCrypto_GetOEMPublicCertificate(public_cert.data(), + &public_cert_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryCreateUsageTableHeaderForHugeHeaderBufferLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t header_buffer_length = buffer_length; + vector usage_table_header(header_buffer_length); + return OEMCrypto_CreateUsageTableHeader(usage_table_header.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeBufferLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeSignatureLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_request_signature_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeCoreMessageLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_core_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +// This verifies that entitled content keys API does not crash for unreasonable +// input message buffer lengths. +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeBufferLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + size_t entitled_key_data_length = + entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_length); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_length); + message.resize(buffer_length); + return entitled_message_.LoadKeys(message); + }; + // We are not constructing a valid message for load entitled content keys. + // Hence skipping status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestDrmKey(&s); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadLicense( + s.session_id(), license_messages.encrypted_response_buffer().data(), + license_messages.encrypted_response_buffer().size(), + license_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadRenewalForHugeResponseLength) { + auto oemcrypto_function = [&](size_t message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_message_size(message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadRenewal( + s.session_id(), renewal_messages.encrypted_response_buffer().data(), + renewal_messages.encrypted_response_buffer().size(), + renewal_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeCoreMessageLength) { + auto oemcrypto_function = [&](size_t core_message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_core_message_size(core_message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); + vector valid_key_id( + license_messages.response_data().keys[0].key_id, + license_messages.response_data().keys[0].key_id + kTestKeyIdMaxLength); + auto oemcrypto_function = [&session_id, + &valid_key_id](size_t additional_key_id_length) { + vector key_id(valid_key_id); + key_id.resize(valid_key_id.size() + additional_key_id_length); + KeyControlBlock block; + size_t size = sizeof(block); + return OEMCrypto_QueryKeyControl(session_id, key_id.data(), key_id.size(), + reinterpret_cast(&block), &size); + }; + // We do not want to stop as soon as API results in an error as it would + // return error on first iteration as key_id is invalid. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_control_block +// length. +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryQueryKeyControlForHugeKeyControlBlockLength) { + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); + uint8_t* key_id = license_messages.response_data().keys[0].key_id; + size_t key_id_length = license_messages.response_data().keys[0].key_id_length; + auto oemcrypto_function = [&session_id, &key_id, + &key_id_length](size_t buffer_length) { + size_t key_control_block_length = buffer_length; + vector key_control_block(key_control_block_length); + return OEMCrypto_QueryKeyControl(session_id, key_id, key_id_length, + key_control_block.data(), + &key_control_block_length); + }; + 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](size_t hash_length) { + uint32_t frame_number = 1; + vector hash_buffer(hash_length); + return OEMCrypto_SetDecryptHash(session_id, frame_number, + hash_buffer.data(), hash_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(f, kCheckStatus); +} + +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); + LoadLicense(); + MakeBuffers(); + EncryptData(); + OEMCryptoResult result = DecryptCENC(); + FreeSecureBuffers(); + // Closing the session and opening it for next iteration. + // If it is last iteration, session will be closed in teardown method of + // class. + session_.close(); + session_.open(); + InstallTestDrmKey(&session_); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); + + // Avoid double free when test teardown calls FreeSecureBuffers() + MakeBuffers(); +} + +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); + LoadLicense(); + MakeBuffers(); + EncryptData(); + OEMCryptoResult result = DecryptCENC(); + FreeSecureBuffers(); + // Closing the session and opening it for next iteration. + // If it is last iteration, session will be closed in teardown method of + // class. + session_.close(); + session_.open(); + InstallTestDrmKey(&session_); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); + + // Avoid double free when test teardown calls FreeSecureBuffers() + MakeBuffers(); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + vector signature(signature_size); + size_t wrapped_private_key_length = 0; + // Find wrapped_private_key_length. + OEMCrypto_LoadProvisioning( + s.session_id(), + 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); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + 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(), + &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeWrappedRsaKeyLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + size_t wrapped_private_key_length = buffer_length; + vector wrapped_private_key(wrapped_private_key_length); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + provisioning_messages.response_signature().data(), + provisioning_messages.response_signature().size(), + wrapped_private_key.data(), &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLength) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer = wrapped_rsa_key_; + wrapped_rsa_key_buffer.resize(wrapped_rsa_key_length); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_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(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLengthStartingFromLength1) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_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, !kCheckStatus); +} + +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(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_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_F(OEMCryptoLoadsCertificateAlternates, + OEMCryptoMemoryGenerateRSASignatureForHugeBuffer) { + OEMCryptoResult sts; + LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) { + ASSERT_TRUE(key_loaded_); + } + if (key_loaded_) { + // 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_)); + + vector message_buffer(10); + size_t signature_length = 0; + sts = OEMCrypto_GenerateRSASignature(s.session_id(), message_buffer.data(), + message_buffer.size(), nullptr, + &signature_length, kSign_PKCS1_Block1); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_NE(static_cast(0), signature_length); + vector signature(signature_length); + + auto oemcrypto_function = [&](size_t buffer_length) { + message_buffer.resize(buffer_length); + return OEMCrypto_GenerateRSASignature( + s.session_id(), message_buffer.data(), message_buffer.size(), + signature.data(), &signature_length, kSign_PKCS1_Block1); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); + } +} + +TEST_F(OEMCryptoLoadsCertificateAlternates, + OEMCryptoMemoryGenerateRSASignatureForHugeSignatureLength) { + LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) { + ASSERT_TRUE(key_loaded_); + } + if (key_loaded_) { + // 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_)); + + vector message_buffer(50); + vector signature; + auto oemcrypto_function = [&](size_t signature_length) { + signature.resize(signature_length); + return OEMCrypto_GenerateRSASignature( + s.session_id(), message_buffer.data(), message_buffer.size(), + signature.data(), &signature_length, kSign_PKCS1_Block1); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); + } +} + +TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) { + EncryptAndLoadKeys(); + OEMCrypto_SESSION session_id = session_.session_id(); + auto oemcrypto_function = [session_id](size_t key_id_length) { + vector key_id(key_id_length); + vector key_handle; + return GetKeyHandleIntoVector(session_id, key_id.data(), key_id.size(), + OEMCrypto_CipherMode_CENC, key_handle); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyEncryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 0; + vector expected_encrypted; + vector key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + 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& iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { + vector buffer(buffer_length); + return OEMCrypto_Generic_Encrypt( + key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyDecryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 1; + vector key_handle; + 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 iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { + vector encrypted(buffer_length); + vector resultant(encrypted.size()); + + return OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv, + OEMCrypto_AES_CBC_128_NO_PADDING, + resultant.data()); + }; + // API expects length to be multiple of 16. Starting from 16. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + vector key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + 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, + &signature_length](size_t buffer_length) { + vector buffer(buffer_length); + return OEMCrypto_Generic_Sign( + key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), &signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeySignForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + vector key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + 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); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + vector key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); + auto oemcrypto_function = [&](size_t buffer_length) { + vector buffer(buffer_length); + vector signature; + SignBuffer(key_index, buffer, &signature); + return GenericVerify(key_handle.data(), key_handle.size(), buffer.data(), + buffer.size(), OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + vector signature; + SignBuffer(key_index, clear_buffer_, &signature); + + vector key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + 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, + &signature](size_t signature_length) { + return OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeHeaderBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector encrypted_usage_entry(entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &buffer_length, + encrypted_usage_entry.data(), &entry_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(header_buffer_length); + vector encrypted_usage_entry(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &header_buffer_length, + encrypted_usage_entry.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryDeactivateUsageEntryForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + std::string pst("pst"); + pst.resize(buffer_length); + entry.license_messages().set_pst(pst); + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + return OEMCrypto_DeactivateUsageEntry( + s.session_id(), reinterpret_cast(pst.c_str()), + pst.length()); + }; + // The test setup assertions fails if pst length goes beyond kMaxPSTLength. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, kMaxPSTLength, + kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeader) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, + encrypted_usage_header_.size(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_P( + OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeaderStartingHeaderLengthFrom1) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + Session& s = entry.session(); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + if (buffer_length < s.encrypted_usage_entry().size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + Session s2; + s2.open(); + InstallTestDrmKey(&s2); + vector encrypted_usage_entry(buffer_length); + memcpy(encrypted_usage_entry.data(), s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size()); + const uint32_t usage_entry_number = s.usage_entry_number(); + return OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, + encrypted_usage_entry.data(), + encrypted_usage_entry.size()); + }; + // We cannot generate an encrypted usage enctry of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_report_usage_fuzz_seed_corpus"); + AppendToFile(file_name, reinterpret_cast(&length), + sizeof(length)); + AppendToFile(file_name, entry.pst().c_str(), entry.pst().length()); + } + vector pst_report_buffer(buffer_length); + return OEMCrypto_ReportUsage( + s.session_id(), reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), pst_report_buffer.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + vector pst_report_buffer(length); + vector pst(buffer_length); + return OEMCrypto_ReportUsage(s.session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), &length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryShrinkUsageTableHeaderForHugeHeaderBufferLength) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + size_t header_buffer_length = buffer_length; + encrypted_usage_header_.resize(header_buffer_length); + return OEMCrypto_ShrinkUsageTableHeader(1, encrypted_usage_header_.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} +/// @} + +} // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_security_tests.gypi b/oemcrypto/test/oemcrypto_security_tests.gypi new file mode 100644 index 0000000..fda1b75 --- /dev/null +++ b/oemcrypto/test/oemcrypto_security_tests.gypi @@ -0,0 +1,69 @@ +# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine License +# Agreement. +# +# Include this in any custom security test targets. +# Does not include the test runner main. +{ + 'variables': { + 'test_opk_serialization_version%' : 'false', + 'static_libcpp%' : 'false', + }, + 'sources': [ + 'oec_device_features.cpp', + 'oec_decrypt_fallback_chain.cpp', + 'oec_key_deriver.cpp', + 'oec_session_util.cpp', + 'oemcrypto_corpus_generator_helper.cpp', + 'oemcrypto_session_tests_helper.cpp', + 'oemcrypto_security_test.cpp', + ], + 'conditions': [ + ['test_opk_serialization_version=="true"', { + 'sources+' : [ + 'oemcrypto_serialization_version_test.cpp', + ], + }], + ['static_libcpp=="true"', { + 'ldflags+':[ + '-static-libstdc++', + ], + }], + ], + 'include_dirs': [ + '<(util_dir)/include', + '<(util_dir)/test', + '<(oemcrypto_dir)/include', + '<(oemcrypto_dir)/ref/src', + '<(oemcrypto_dir)/test', + '<(oemcrypto_dir)/test/fuzz_tests', + '<(oemcrypto_dir)/odk/include', + '<(oemcrypto_dir)/util/include', + ], + 'defines': [ + 'OEMCRYPTO_TESTS', + ], + 'conditions': [ + ['support_ota_keybox_functions=="true"', { + 'sources': [ + '<(oemcrypto_dir)/test/ota_keybox_test.cpp', + ], + }], + ['generate_code_coverage_report=="true"', { + # Include flags to generate source based code coverage reports. + 'cflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + 'ldflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + }], + ], + 'dependencies': [ + '<(oemcrypto_dir)/odk/src/odk.gyp:odk', + '<(oemcrypto_dir)/util/oec_ref_util.gyp:oec_ref_util', + ], + 'includes': [ '../../util/libssl_dependency.gypi' ], +} diff --git a/oemcrypto/test/oemcrypto_serialization_version_test.cpp b/oemcrypto/test/oemcrypto_serialization_version_test.cpp index 31bfacb..9bc71ec 100644 --- a/oemcrypto/test/oemcrypto_serialization_version_test.cpp +++ b/oemcrypto/test/oemcrypto_serialization_version_test.cpp @@ -9,6 +9,7 @@ #include "OEMCryptoCENC.h" #include "log.h" +#include "odk_structs.h" #include "oec_test_data.h" using namespace std; @@ -26,6 +27,7 @@ class OEMCryptoTest : public ::testing::Test { LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + OEMCrypto_EnterTestMode(); } void TearDown() override { diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.cpp b/oemcrypto/test/oemcrypto_session_tests_helper.cpp index f84e37c..48e163f 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.cpp +++ b/oemcrypto/test/oemcrypto_session_tests_helper.cpp @@ -20,16 +20,23 @@ const uint8_t* find(const vector& message, return &(*pos); } -// This creates a wrapped RSA key. -void SessionUtil::CreateWrappedRSAKey() { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key(); +void SessionUtil::CreateWrappedDRMKey() { + if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + // Have the device create a wrapped key. + CreateProv4DRMKey(); + } else { + // Create a wrapped RSA key from encoded_rsa_key_. + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); + wrapped_drm_key_ = provisioning_messages.wrapped_rsa_key(); + drm_key_type_ = OEMCrypto_RSA_Private_Key; + drm_public_key_.clear(); + } } void SessionUtil::InstallKeybox(const wvoec::WidevineKeybox& keybox, @@ -48,7 +55,7 @@ void SessionUtil::InstallKeybox(const wvoec::WidevineKeybox& keybox, } } -void SessionUtil::EnsureTestKeys() { +void SessionUtil::EnsureTestROT() { switch (global_features.derive_key_method) { case DeviceFeatures::LOAD_TEST_KEYBOX: keybox_ = kTestKeybox; @@ -73,51 +80,91 @@ void SessionUtil::EnsureTestKeys() { // This makes sure that the derived keys (encryption key and two mac keys) // are installed in OEMCrypto and in the test session. -void SessionUtil::InstallTestRSAKey(Session* s) { - if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - if (wrapped_rsa_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. - const size_t buffer_size = 5000; // Make sure it is large enough. - std::vector public_key(buffer_size); - size_t public_key_size = buffer_size; - std::vector public_key_signature(buffer_size); - size_t public_key_signature_size = buffer_size; - std::vector wrapped_private_key(buffer_size); - size_t wrapped_private_key_size = buffer_size; - OEMCrypto_PrivateKeyType key_type; - // Assume OEM cert has been loaded. - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GenerateCertificateKeyPair( - s->session_id(), public_key.data(), &public_key_size, - public_key_signature.data(), &public_key_signature_size, - wrapped_private_key.data(), &wrapped_private_key_size, - &key_type)); - // Assume the public key has been verified by the server and the DRM cert - // is returned. - wrapped_private_key.resize(wrapped_private_key_size); - public_key.resize(public_key_size); - wrapped_rsa_key_ = wrapped_private_key; - drm_public_key_ = public_key; - key_type_ = key_type; - } - ASSERT_NO_FATAL_FAILURE(s->LoadWrappedDrmKey(key_type_, wrapped_rsa_key_)); - ASSERT_NO_FATAL_FAILURE(s->SetPublicKeyFromSubjectPublicKey( - key_type_, drm_public_key_.data(), drm_public_key_.size())); - return; - } - +void SessionUtil::InstallTestDrmKey(Session* s) { if (global_features.loads_certificate) { - 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(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); } - // Load the wrapped rsa test key. - ASSERT_NO_FATAL_FAILURE(s->LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + // Load the wrapped drm test key. + ASSERT_NO_FATAL_FAILURE( + s->LoadWrappedDrmKey(drm_key_type_, wrapped_drm_key_)); + if (drm_public_key_.size() > 0) { + ASSERT_NO_FATAL_FAILURE(s->SetPublicKeyFromSubjectPublicKey( + drm_key_type_, drm_public_key_.data(), drm_public_key_.size())); + } else { + ASSERT_NO_FATAL_FAILURE(s->SetPublicKeyFromPrivateKeyInfo( + drm_key_type_, encoded_rsa_key_.data(), encoded_rsa_key_.size())); + } + } else { + // Test RSA key should be loaded. + ASSERT_NO_FATAL_FAILURE(s->SetTestRsaPublicKey()); } - // Test RSA key should be loaded. - ASSERT_NO_FATAL_FAILURE(s->SetTestRsaPublicKey()); +} + +// Generate OEM key pair, craft a provisioning 4.0 OEM cert request, sign it +// with the OEM private key and verify the signature. Finally, install OEM +// private to session s. +void SessionUtil::CreateProv4OEMKey(Session* s) { + ASSERT_NE(s, nullptr); + if (global_features.provisioning_method != OEMCrypto_BootCertificateChain) { + FAIL() << "Provisioning 4.0 is required."; + } + Provisioning40RoundTrip provisioning_messages(s); + // Generate key pair. + ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(true)); + // Need OEM public key to verify the signed request. + ASSERT_NO_FATAL_FAILURE(s->SetPublicKeyFromSubjectPublicKey( + provisioning_messages.oem_key_type(), + provisioning_messages.oem_public_key().data(), + provisioning_messages.oem_public_key().size())); + // Save the generated keys, which will be used by DRM cert provisioning later. + wrapped_oem_key_ = provisioning_messages.wrapped_oem_key(); + oem_public_key_ = provisioning_messages.oem_public_key(); + oem_key_type_ = provisioning_messages.oem_key_type(); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + // Install OEM private key into the session. + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadOEMCertResponse()); +} + +// Generate DRM key pair, craft a provisioning 4.0 DRM cert request, sign it +// with the OEM private key and verify the signature. Finally, install DRM +// private to session s. An OEM cert needs to be installed first. It is also +// done in this function. +void SessionUtil::CreateProv4DRMKey() { + if (global_features.provisioning_method != OEMCrypto_BootCertificateChain) { + FAIL() << "Provisioning 4.0 is required."; + } + // Provision OEM key first. + if (wrapped_oem_key_.size() == 0) { + Session oem_session; + ASSERT_NO_FATAL_FAILURE(oem_session.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&oem_session)); + } + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_InstallOemPrivateKey( + s.session_id(), oem_key_type_, + reinterpret_cast(wrapped_oem_key_.data()), + wrapped_oem_key_.size())); + ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey( + oem_key_type_, oem_public_key_.data(), oem_public_key_.size())); + + // Provision DRM key. + Provisioning40RoundTrip provisioning_messages(&s); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(false)); + // Need DRM public key to verify DRM request signature. + ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey( + provisioning_messages.drm_key_type(), + provisioning_messages.drm_public_key().data(), + provisioning_messages.drm_public_key().size())); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadDRMCertResponse()); + wrapped_drm_key_ = provisioning_messages.wrapped_drm_key(); + drm_key_type_ = provisioning_messages.drm_key_type(); + drm_public_key_ = provisioning_messages.drm_public_key(); } } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.h b/oemcrypto/test/oemcrypto_session_tests_helper.h index 6ceb03a..b29f37e 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.h +++ b/oemcrypto/test/oemcrypto_session_tests_helper.h @@ -1,3 +1,6 @@ +#ifndef CDM_OEMCRYPTO_SESSION_TESTS_HELPER_ +#define CDM_OEMCRYPTO_SESSION_TESTS_HELPER_ + #include #include #include @@ -17,8 +20,10 @@ class SessionUtil { kTestRSAPKCS8PrivateKeyInfo2_2048 + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)) {} - // Create a new wrapped DRM Certificate. - void CreateWrappedRSAKey(); + // Create a new wrapped DRM Certificate. This creates a new one, even if one + // already exists. For provisioning 2 or 3, it uses encoded_rsa_key_ to + // specify the key. For Prov 4.0, the key is generated by OEMCrypto. + void CreateWrappedDRMKey(); // This is used to force installation of a keybox. This overwrites the // production keybox -- it does NOT use OEMCrypto_LoadTestKeybox. @@ -26,15 +31,31 @@ class SessionUtil { // This loads the test keybox or the test RSA key, using LoadTestKeybox or // LoadTestRSAKey as needed. - void EnsureTestKeys(); + void EnsureTestROT(); - void InstallTestRSAKey(Session* s); + // Install a DRM private key in to the session. If a key has not been created, + // tehn CreateWrappedDRMKey is used to create one first. Works with Prov 2-4. + void InstallTestDrmKey(Session* s); + // Create and install an OEM Cert private key. After creation, the key is + // saved to oem_public_key_. Only for provisioning 4.0 + void CreateProv4OEMKey(Session* s); + + // Create a new DRM Cert. Only for provisioning 4.0 + void CreateProv4DRMKey(); + + // Used by prov2.0, prov3.0, and prov 4.0 std::vector encoded_rsa_key_; - std::vector wrapped_rsa_key_; - OEMCrypto_PrivateKeyType key_type_; + std::vector wrapped_drm_key_; + OEMCrypto_PrivateKeyType drm_key_type_; std::vector drm_public_key_; wvoec::WidevineKeybox keybox_; + + // Used by prov4.0 + std::vector wrapped_oem_key_; + std::vector oem_public_key_; + OEMCrypto_PrivateKeyType oem_key_type_; }; } // namespace wvoec +#endif // CDM_OEMCRYPTO_SESSION_TESTS_HELPER_ diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 2ae9f8c..01647b0 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -12,6 +12,11 @@ * @defgroup basic Basic Functionality Tests * Basic functionality tests. * + * @defgroup provision Provisioning Tests + * Test for provisioning and certificate key processing. These tests cover + * Provsioning 2.0, 3.0 and 4.0. Tests for the wrong provisioning scheme should + * be skipped. + * * @defgroup license License Request Tests * Test for requesting and loading licenses. * @@ -23,6 +28,21 @@ * * @defgroup usage_table Usage Table Tests * Tests that use the usage table. + * + * @defgroup entitle Entitlement License tests + * Tests for entitlement licenses. + * + * @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 generic Generic Crypto Tests + * Tests for the Generic Crypto functionality. + * + * @defgroup security Security Tests + * Buffer overflow tests, off-by-one tests, and other security tests. */ #include @@ -53,10 +73,15 @@ #include "oec_extra_test_keys.h" #include "oec_session_util.h" #include "oec_test_data.h" +#include "oemcrypto_basic_test.h" #include "oemcrypto_corpus_generator_helper.h" #include "oemcrypto_fuzz_structs.h" +#include "oemcrypto_license_test.h" +#include "oemcrypto_provisioning_test.h" +#include "oemcrypto_resource_test.h" #include "oemcrypto_session_tests_helper.h" #include "oemcrypto_types.h" +#include "oemcrypto_usage_table_test.h" #include "platform.h" #include "string_conversions.h" #include "test_sleep.h" @@ -101,1594 +126,10 @@ void PrintTo(const tuple -T GetResourceValue(T (&resource_values)[N]) { - if (global_features.resource_rating < 1) return resource_values[0]; - if (global_features.resource_rating > N) return resource_values[N - 1]; - return resource_values[global_features.resource_rating - 1]; -} - -// Used for testing oemcrypto APIs with huge buffers. -typedef const std::function oemcrypto_function; -// Function to test APIs that expect a buffer length as input -// by passing huge buffer lengths upto end_buffer_length and test that the API -// doesn't crash. -void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, - size_t start_buffer_length, - size_t end_buffer_length, - bool check_status) { - OEMCryptoResult sts = OEMCrypto_SUCCESS; - for (size_t buffer_length = start_buffer_length; - buffer_length < end_buffer_length && - (sts == OEMCrypto_SUCCESS || sts == OEMCrypto_ERROR_SHORT_BUFFER || - !check_status); - buffer_length *= 2) { - sts = f(buffer_length); - if (check_status && sts != OEMCrypto_SUCCESS && - sts != OEMCrypto_ERROR_SHORT_BUFFER) { - LOGI("Test exits huge buffer loop for length:%zu, status:%d", - buffer_length, sts); - } - } -} - -// Function to test APIs that expect a buffer length as input -// by passing huge buffer lengths upto kHugeInputBufferLength and test that -// the API doesn't crash. -void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, bool check_status) { - TestHugeLengthDoesNotCrashAPI(f, 1, kHugeInputBufferLength, check_status); -} - -// After API 16, we require 300 entries in the usage table. Before API 16, we -// required 200. -size_t RequiredUsageSize() { - return global_features.api_version < 16 ? 200 : 300; -} - -// These are the maximum sizes we test. That means it is the minimum size that -// OEMCrypto must support. -// clang-format off -const size_t kMaxSampleSize[] = { 1*MiB, 2*MiB, 4*MiB, 16*MiB}; -const size_t kMaxNumberSubsamples[] = { 10, 16, 32, 64}; -const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB, 4*MiB}; -const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB, 1*MiB}; -const size_t kMaxConcurrentSession[] = { 10, 20, 30, 40}; -const size_t kMaxKeysPerSession[] = { 4, 20, 20, 30}; -const size_t kMaxTotalKeys[] = { 16, 40, 80, 90}; -const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; -const size_t kMaxTotalDRMPrivateKeys[] = { 2, 4, 6, 8}; -// Note: Frame rate and simultaneous playback are specified by resource rating, -// but are tested at the system level, so there are no unit tests for frame -// rate. Similarly, number of subsamples for AV1 -// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576}; -// clang-format on - -// Return a printable string from data. If all the characters are printable, -// then just use the string. Otherwise, convert to hex. -std::string MaybeHex(const uint8_t* data, size_t length) { - for (size_t i = 0; i < length; i++) { - if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); - } - return std::string(reinterpret_cast(data), length); -} -std::string MaybeHex(const std::vector& data) { - return MaybeHex(data.data(), data.size()); -} -} // namespace - -class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { - protected: - OEMCryptoClientTest() {} - - void SetUp() override { - ::testing::Test::SetUp(); - wvutil::TestSleep::SyncFakeClock(); - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); - OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); - } - - void TearDown() override { - OEMCrypto_Terminate(); - ::testing::Test::TearDown(); - } - - const uint8_t* find(const vector& message, - const vector& substring) { - vector::const_iterator pos = search( - message.begin(), message.end(), substring.begin(), substring.end()); - if (pos == message.end()) { - return nullptr; - } - return &(*pos); - } - - OEMCryptoResult CopyBuffer( - OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer, - size_t input_buffer_size, - const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, - uint8_t subsample_flags) { - if (ShouldGenerateCorpus() && input_buffer != nullptr && - dest_buffer_descriptor != nullptr) { - OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; - fuzzed_structure.dest_buffer_desc = *dest_buffer_descriptor; - fuzzed_structure.subsample_flags = subsample_flags; - const std::string file_name = - GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); - // Corpus for copy buffer fuzzer should be in the format: - // (dest_buffer_descriptor | subsample_flags | input_buffer). - AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), - sizeof(fuzzed_structure)); - AppendToFile(file_name, reinterpret_cast(&input_buffer), - input_buffer_size); - } - return OEMCrypto_CopyBuffer(session, input_buffer, input_buffer_size, - dest_buffer_descriptor, subsample_flags); - } -}; - -TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { - Session s; - s.open(); - OEMCrypto_DestBufferDesc output_descriptor; - int secure_fd = kHugeRandomNumber; - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, - secure_fd)); - s.close(); -} - -/// @addtogroup basic +/// @addtogroup security /// @{ -/** - * Verifies initialization and logs version information. - * This test is first, because it might give an idea why other - * tests are failing when the device has the wrong keybox installed. - */ -TEST_F(OEMCryptoClientTest, VersionNumber) { - const std::string log_message = - "OEMCrypto unit tests for API 17.1. Tests last updated 2022-06-17"; - cout << " " << log_message << "\n"; - cout << " " - << "These tests are part of Android T." - << "\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, 17); - EXPECT_EQ(ODK_MINOR_VERSION, 1); - EXPECT_EQ(kCurrentAPI, 17u); - 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; - uint32_t version = OEMCrypto_APIVersion(); - uint32_t minor_version = OEMCrypto_MinorAPIVersion(); - cout << " OEMCrypto API version is " << version << "." - << minor_version << endl; - if (OEMCrypto_SupportsUsageTable()) { - cout << " OEMCrypto supports usage tables" << endl; - } else { - cout << " OEMCrypto does not support usage tables" << endl; - } - if (version >= 15) { - const uint32_t tier = OEMCrypto_ResourceRatingTier(); - cout << " Resource Rating Tier: " << tier << endl; - } - if (version >= 17) { - OEMCryptoResult sts = OEMCrypto_ProductionReady(); - if (sts != OEMCrypto_SUCCESS) { - LOGW("Device is not production ready, returns %d", sts); - } - sts = OEMCrypto_SUCCESS; - std::string build_info; - size_t buf_length = 0; - sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); - if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - build_info.resize(buf_length); - sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - if (build_info.size() != buf_length) { - build_info.resize(buf_length); - } - cout << " BuildInformation: " << build_info << endl; - OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport(); - cout << " WatermarkingSupport: " << support << endl; - } - ASSERT_GE(version, 8u); - ASSERT_LE(version, kCurrentAPI); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryAllocateSecureBufferForHugeBufferSize) { - Session s; - s.open(); - auto oemcrypto_function = [&s](size_t buffer_size) { - OEMCrypto_DestBufferDesc output_descriptor; - int secure_fd; - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - s.session_id(), buffer_size, &output_descriptor, &secure_fd); - if (sts == OEMCrypto_SUCCESS) { - OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, secure_fd); - } - return sts; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); - s.close(); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLength) { - auto oemcrypto_function = [](size_t keybox_length) { - vector keybox_buffer(keybox_length); - size_t wrapped_keybox_length = keybox_length + 50; - vector wrapped_keybox_buffer(wrapped_keybox_length); - vector transport_key_buffer(20); - memcpy(keybox_buffer.data(), &kTestKeybox, sizeof(kTestKeybox)); - return OEMCrypto_WrapKeyboxOrOEMCert( - keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), - &wrapped_keybox_length, transport_key_buffer.data(), - transport_key_buffer.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, sizeof(kTestKeybox), - kHugeInputBufferLength, kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeWrappedKeyboxLength) { - auto oemcrypto_function = [](size_t buffer_length) { - size_t wrapped_keybox_length = buffer_length; - vector wrapped_keybox_buffer(wrapped_keybox_length); - vector transport_key_buffer(20); - return OEMCrypto_WrapKeyboxOrOEMCert( - reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), - wrapped_keybox_buffer.data(), &wrapped_keybox_length, - transport_key_buffer.data(), transport_key_buffer.size()); - }; - // API expects keybox length and wrapped keybox length to be equal. We would - // like to test for various values of wrapped keybox lengths, hence skipping - // status check. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { - auto oemcrypto_function = [](size_t transport_key_length) { - 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( - reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), - wrapped_keybox_buffer.data(), &wrapped_keybox_length, - transport_key_buffer.data(), transport_key_buffer.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F( - OEMCryptoClientTest, - OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLengthStartingFromLength1) { - auto oemcrypto_function = [](size_t keybox_length) { - vector keybox_buffer(keybox_length); - size_t wrapped_keybox_length = keybox_length + 50; - vector wrapped_keybox_buffer(wrapped_keybox_length); - vector transport_key_buffer(20); - return OEMCrypto_WrapKeyboxOrOEMCert( - keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), - &wrapped_keybox_length, transport_key_buffer.data(), - transport_key_buffer.size()); - }; - // Cannot check status as keybox will not be valid for this test. - // We still want to test what happens if buffer lengths is less that keybox - // length. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -/** - * The resource rating is a number from 1 to 4. The first three levels - * were initially defined in API 15 and they were expanded in API 16. - */ -TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) { - ASSERT_GE(OEMCrypto_ResourceRatingTier(), 1u); - ASSERT_LE(OEMCrypto_ResourceRatingTier(), 4u); -} - -/** - * OEMCrypto must declare what type of provisioning scheme it uses. - */ -TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { - OEMCrypto_ProvisioningMethod provisioning_method = - OEMCrypto_GetProvisioningMethod(); - cout << " Provisioning method = " - << ProvisioningMethodName(provisioning_method) << endl; - ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method); -} - -const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { - switch (value) { - case HDCP_NONE: - return "No HDCP supported, no secure data path"; - case HDCP_V1: - return "HDCP version 1.x"; - case HDCP_V1_0: - return "HDCP version 1.0"; - case HDCP_V1_1: - return "HDCP version 1.1"; - case HDCP_V1_2: - return "HDCP version 1.2"; - case HDCP_V1_3: - return "HDCP version 1.3"; - case HDCP_V1_4: - return "HDCP version 1.4"; - case HDCP_V2: - return "HDCP version 2.0"; - case HDCP_V2_1: - return "HDCP version 2.1"; - case HDCP_V2_2: - return "HDCP version 2.2"; - case HDCP_V2_3: - return "HDCP version 2.3"; - case HDCP_NO_DIGITAL_OUTPUT: - return "No HDCP device attached/using local display with secure path"; - default: - return ""; - } -} - -TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) { - OEMCryptoResult sts; - OEMCrypto_HDCP_Capability current, maximum; - sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - printf(" Current HDCP Capability: 0x%02x = %s.\n", - static_cast(current), HDCPCapabilityAsString(current)); - printf(" Maximum HDCP Capability: 0x%02x = %s.\n", - static_cast(maximum), HDCPCapabilityAsString(maximum)); -} - -TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { - // This just tests some trivial functionality of the SRM update functions. - uint16_t version = 0; - OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version); - if (current_result == OEMCrypto_SUCCESS) { - printf(" Current SRM Version: %d.\n", version); - EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr)); - } else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) { - printf(" Current SRM Status: Local Display Only.\n"); - } else { - EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result); - } -} - -TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) { - OEMCryptoResult sts; - std::string build_info; - sts = OEMCrypto_BuildInformation(&build_info[0], nullptr); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); - size_t buf_length = 0; - sts = OEMCrypto_BuildInformation(nullptr, &buf_length); - // Previous versions of the test expected the wrong error code. - // Although OEMCrypto_ERROR_INVALID_CONTEXT is still accepted by - // the tests, vendors should return OEMCrypto_ERROR_SHORT_BUFFER if - // |buffer| is null and |buf_length| is zero, assigning - // the correct length to |buf_length|. - // TODO(231514699): Remove case for ERROR_INVALID_CONTEXT. - ASSERT_TRUE(OEMCrypto_ERROR_SHORT_BUFFER == sts || - OEMCrypto_ERROR_INVALID_CONTEXT == sts); - if (sts == OEMCrypto_ERROR_INVALID_CONTEXT) { - printf( - "Warning: OEMCrypto_BuildInformation should return " - "ERROR_SHORT_BUFFER.\n"); - } - if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - constexpr size_t kZero = 0; - ASSERT_GT(buf_length, kZero); - } -} - -TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { - size_t sessions_count; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); - ASSERT_EQ(0u, sessions_count); - size_t maximum; - OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - printf(" Max Number of Sessions: %zu.\n", maximum); - size_t required_max = GetResourceValue(kMaxConcurrentSession); - ASSERT_GE(maximum, required_max); -} - -TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) { - const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); - printf(" Max Usage Table Size: %zu.\n", maximum); - // A maximum of 0 means the table is constrained by dynamic memory allocation. - if (maximum > 0) { - ASSERT_GE(maximum, RequiredUsageSize()); - } -} - -// -// initialization tests -// -TEST_F(OEMCryptoClientTest, NormalInitTermination) { - // Should be able to terminate OEMCrypto, and then restart it. - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); - OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); -} - -// Test that set sandbox doesn't crash for a large sandbox id leangth. -TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForHugeSandboxIdLength) { - auto oemcrypto_function = [](size_t buffer_length) { - vector buffer(buffer_length); - return OEMCrypto_SetSandbox(buffer.data(), buffer.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) { - OEMCryptoResult sts; - OEMCrypto_DTCP2_Capability capability; - sts = OEMCrypto_GetDTCP2Capability(&capability); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - switch (capability) { - case OEMCrypto_NO_DTCP2: - printf(" Current DTCP Support: DTCP2 not supported.\n"); - break; - case OEMCrypto_DTCP2_V1: - printf( - " Current DTCP Support: Version 1 (or higher) of " - "DTCP2 is supported.\n"); - break; - } -} - -// -// Session Tests -// -TEST_F(OEMCryptoClientTest, NormalSessionOpenClose) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.close()); -} - -TEST_F(OEMCryptoClientTest, TwoSessionsOpenClose) { - Session s1; - Session s2; - ASSERT_NO_FATAL_FAILURE(s1.open()); - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s1.close()); - ASSERT_NO_FATAL_FAILURE(s2.close()); -} - -// This test verifies that OEMCrypto can open approximately as many sessions as -// it claims. -TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) { - size_t sessions_count; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); - ASSERT_EQ(0u, sessions_count); - size_t max_sessions; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetMaxNumberOfSessions(&max_sessions)); - // We expect OEMCrypto implementations support at least this many sessions. - size_t required_number = GetResourceValue(kMaxConcurrentSession); - ASSERT_GE(max_sessions, required_number); - // We allow GetMaxNumberOfSessions to return an estimate. This tests with a - // pad of 5%. Even if it's just an estimate, we still require 8 sessions. - size_t max_sessions_with_pad = max(max_sessions * 19 / 20, required_number); - vector sessions; - // Limit the number of sessions for testing. - const size_t kMaxNumberOfSessionsForTesting = 0x100u; - for (size_t i = 0; i < kMaxNumberOfSessionsForTesting; i++) { - OEMCrypto_SESSION session_id; - OEMCryptoResult sts = OEMCrypto_OpenSession(&session_id); - // GetMaxNumberOfSessions might be an estimate. We allow OEMCrypto to report - // a max that is less than what is actually supported. Assume the number - // returned is |max|. OpenSessions shall not fail if number of active - // sessions is less than |max|; OpenSessions should fail with - // OEMCrypto_ERROR_TOO_MANY_SESSIONS if too many sessions are open. - if (sts != OEMCrypto_SUCCESS) { - ASSERT_EQ(OEMCrypto_ERROR_TOO_MANY_SESSIONS, sts); - ASSERT_GE(i, max_sessions_with_pad); - break; - } - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); - ASSERT_EQ(i + 1, sessions_count); - sessions.push_back(session_id); - } - for (size_t i = 0; i < sessions.size(); i++) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(sessions[i])); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetNumberOfOpenSessions(&sessions_count)); - ASSERT_EQ(sessions.size() - i - 1, sessions_count); - } - if (sessions.size() == kMaxNumberOfSessionsForTesting) { - printf( - " MaxSessionsOpenClose: reaches " - "kMaxNumberOfSessionsForTesting(%zu). GetMaxNumberOfSessions = %zu. " - "ERROR_TOO_MANY_SESSIONS not tested.", - kMaxNumberOfSessionsForTesting, max_sessions); - } -} - -// Verify that GetRandom does work, and does some sanity checks on how random -// the data is. Basically, we say that calling GetRandom twice should not -// generate much overlap. -TEST_F(OEMCryptoClientTest, GetRandomLargeBuffer) { - // 32 bytes. Not very large, but that's all we really need in one call. - const size_t size = 32; - uint8_t data1[size]; - uint8_t data2[size]; - memset(data1, 0, size); - memset(data2, 0, size); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetRandom(data1, size)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetRandom(data2, size)); - // We don't have enough data to see that the data is really random, - // so we'll just do a spot check that two calls don't return the same values. - int count = 0; - for (size_t i = 0; i < size; i++) { - if (data1[i] == data2[i]) count++; - } - ASSERT_LE(count, 6); // P(count > 6) = 4.3e-11 -} - -// Verify that GetRandom doesn't crash for large input lengths. -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForHugeBuffer) { - auto oemcrypto_function = [](size_t buffer_length) { - vector buffer(buffer_length); - // TODO(ellurubharath, fredgc): Need to re-evaluate this on a real device - // as GetRandom can be slow. - return OEMCrypto_GetRandom(buffer.data(), buffer.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, GenerateNonce) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(); -} - -// Prevent a nonce flood even if each nonce is in a different session. -TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { - int error_counter = 0; - const int64_t test_start = wvutil::Clock().GetCurrentTime(); - // More than 200 nonces per second should generate an error. - // To allow for some slop, we actually test for more. - const int flood_cutoff = 200; - const int loop_count = flood_cutoff * 2; - for (int i = 0; i < loop_count; i++) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(&error_counter); - } - const int64_t test_end = wvutil::Clock().GetCurrentTime(); - int valid_counter = loop_count - error_counter; - // Either oemcrypto should enforce a delay, or it should return an error from - // GenerateNonce -- in either case the number of valid nonces is rate - // limited. We add two seconds to allow for round off error in both - // test_start and test_end. - EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); - error_counter = 0; - // After a pause, we should be able to regenerate nonces. - wvutil::TestSleep::Sleep(2); - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(&error_counter); - EXPECT_EQ(0, error_counter); -} - -// Prevent a nonce flood even if some nonces are in a different session. This -// is different from the test above because there are several session open at -// the same time. We want to make sure you can't get a flood of nonces by -// opening a flood of sessions. -TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { - int request_counter = 0; - int error_counter = 0; - const int64_t test_start = wvutil::Clock().GetCurrentTime(); - // More than 200 nonces per second should generate an error. - // To allow for some slop, we actually test for more. - const int flood_cutoff = 200; - const size_t session_count = GetResourceValue(kMaxConcurrentSession); - const size_t loop_count = 2 * flood_cutoff / session_count + 1; - for (size_t i = 0; i < loop_count; i++) { - std::vector s(session_count); - for (size_t j = 0; j < session_count; j++) { - ASSERT_NO_FATAL_FAILURE(s[j].open()); - request_counter++; - s[j].GenerateNonce(&error_counter); - } - } - const int64_t test_end = wvutil::Clock().GetCurrentTime(); - int valid_counter = request_counter - error_counter; - // Either oemcrypto should enforce a delay, or it should return an error from - // GenerateNonce -- in either case the number of valid nonces is rate - // limited. We add two seconds to allow for round off error in both - // test_start and test_end. - EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); - error_counter = 0; - // After a pause, we should be able to regenerate nonces. - wvutil::TestSleep::Sleep(2); - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(&error_counter); - EXPECT_EQ(0, error_counter); -} - -// This verifies that CopyBuffer works, even before a license has been loaded. -TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - const int kDataSize = 256; - vector input_buffer(kDataSize); - GetRandBytes(input_buffer.data(), input_buffer.size()); - vector output_buffer(kDataSize); - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.clear_buffer_length = - output_buffer.size(); - ASSERT_EQ(OEMCrypto_SUCCESS, - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - ASSERT_EQ(input_buffer, output_buffer); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - CopyBuffer(s.session_id(), nullptr, input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - dest_buffer_descriptor.buffer.clear.clear_buffer = nullptr; - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.clear_buffer_length = - output_buffer.size() - 1; - ASSERT_NE(OEMCrypto_SUCCESS, - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); -} - -// This verifies that CopyBuffer works on the maximum required buffer size. -TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - size_t max_size = GetResourceValue(kMaxSubsampleSize); - vector input_buffer(max_size); - GetRandBytes(input_buffer.data(), input_buffer.size()); - vector output_buffer(max_size); - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.clear_buffer_length = - output_buffer.size(); - ASSERT_EQ(OEMCrypto_SUCCESS, - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - ASSERT_EQ(input_buffer, output_buffer); -} - -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForHugeBufferLengths) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector input_buffer; - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; - - auto oemcrypto_function = [&s, &dest_buffer_descriptor, - &input_buffer](size_t buffer_length) { - input_buffer.resize(buffer_length); - int secure_fd; - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - s.session_id(), buffer_length, &dest_buffer_descriptor, &secure_fd); - if (sts != OEMCrypto_SUCCESS) { - LOGI("Secure buffers are not supported."); - return sts; - } - - dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; - OEMCryptoResult status = OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), buffer_length, - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); - OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, - secure_fd); - return status; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryCopyBufferDirectForHugeBufferLengths) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector input_buffer; - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Direct; - dest_buffer_descriptor.buffer.direct.is_video = false; - - auto oemcrypto_function = [&s, &dest_buffer_descriptor, - &input_buffer](size_t buffer_length) { - input_buffer.resize(buffer_length); - OEMCryptoResult status = OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), buffer_length, - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); - return status; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForOutOfRangeOffset) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector input_buffer; - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; - - size_t buffer_length = KiB; - input_buffer.resize(buffer_length); - int secure_fd; - if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length, - &dest_buffer_descriptor, - &secure_fd) != OEMCrypto_SUCCESS) { - LOGI("Secure buffers are not supported."); - return; - } - - dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; - auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer, - &buffer_length](size_t offset) { - dest_buffer_descriptor.buffer.secure.offset = offset; - return OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), buffer_length, - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); - OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, - secure_fd); -} - -TEST_F(OEMCryptoClientTest, - OEMCryptoMemoryCopyBufferForOutOfRangeHandleLength) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector input_buffer; - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; - - size_t buffer_length = KiB; - input_buffer.resize(buffer_length); - int secure_fd; - if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length, - &dest_buffer_descriptor, - &secure_fd) != OEMCrypto_SUCCESS) { - LOGI("Secure buffers are not supported."); - return; - } - - dest_buffer_descriptor.buffer.secure.secure_buffer_length = - kHugeInputBufferLength; - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), buffer_length, - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, - secure_fd); -} - -TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) { - uint8_t oemcrypto_invalid_subsample_flag = 85; - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - size_t max_size = GetResourceValue(kMaxSubsampleSize); - vector input_buffer(max_size); - GetRandBytes(input_buffer.data(), input_buffer.size()); - vector output_buffer(max_size); - OEMCrypto_DestBufferDesc dest_buffer_descriptor; - dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.clear_buffer_length = - output_buffer.size(); - ASSERT_NO_FATAL_FAILURE( - CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); -} - -TEST_F(OEMCryptoClientTest, CanLoadTestKeys) { - ASSERT_NE(DeviceFeatures::NO_METHOD, global_features.derive_key_method) - << "Session tests cannot run with out a test keybox or RSA cert."; -} - -// Tests using this class are only used for devices with a keybox. They are not -// run for devices with an OEM Certificate. -class OEMCryptoKeyboxTest : public OEMCryptoClientTest { - void SetUp() override { - OEMCryptoClientTest::SetUp(); - OEMCryptoResult sts = OEMCrypto_IsKeyboxValid(); - // If the production keybox is valid, use it for these tests. Most of the - // other tests will use a test keybox anyway, but it's nice to check the - // device ID for the real keybox if we can. - if (sts == OEMCrypto_SUCCESS) return; - printf("Production keybox is NOT valid. All tests use test keybox.\n"); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_LoadTestKeybox(reinterpret_cast(&kTestKeybox), - sizeof(kTestKeybox))); - } -}; - -/******** Dangerous Tests - DO NOT RUN ***********/ -/*The following tests try to test InstallKeybox API with random buffers of -varying length in order to catch any overflow issues. These tests override the -actual keybox on the device. Remove the if and endif statement to run these -tests on a device ONLY IF YOU ARE ABLE TO RECOVER THE KEYBOX on the device.*/ -#if 0 -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer) { - auto f = [](size_t keybox_length) { - vector keybox(keybox_length); - memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox)); - return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); - }; - // Starting at sizeof(kTestKeybox) as we are copying valid keybox - // at beginning of generated buffers. - TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength, - kCheckStatus); -} - -TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryInstallKeyboxForHugeKeyboxBufferStartingFromLength1) { - auto f = [](size_t keybox_length) { - vector keybox(keybox_length); - return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); - }; - // We are testing for keybox lengths starting from 1 which would return error, - // hence skipping status check. - TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); -} -#endif - -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { - auto f = [](size_t keybox_length) { - vector keybox(keybox_length); - memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox)); - return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); - }; - // Starting at sizeof(kTestKeybox) as we are copying valid keybox - // at beginning of generated buffers. - TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength, - kCheckStatus); -} - -TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBufferStartingFromLength1) { - auto f = [](size_t keybox_length) { - vector keybox(keybox_length); - return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); - }; - // We are testing for keybox lengths starting from 1 which would return error, - // hence skipping status check. - TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); -} - -// This test is used to print the device ID to stdout. -TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { - OEMCryptoResult sts; - uint8_t dev_id[128] = {0}; - size_t dev_id_len = 128; - sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - cout << " NormalGetDeviceId: dev_id = " - << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; -} - -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetDeviceIdForHugeIdLength) { - auto oemcrypto_function = [](size_t input_length) { - size_t device_id_length = input_length; - vector device_id(device_id_length); - return OEMCrypto_GetDeviceID(device_id.data(), &device_id_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) { - OEMCryptoResult sts; - uint8_t dev_id[128]; - for (int i = 0; i < 128; ++i) { - dev_id[i] = 0x55; - } - dev_id[127] = '\0'; - size_t dev_id_len = 0; - sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - // On short buffer error, function should return minimum buffer length - ASSERT_GT(dev_id_len, 0u); - // Should also return short buffer if passed a zero length and a null buffer. - dev_id_len = 0; - sts = OEMCrypto_GetDeviceID(nullptr, &dev_id_len); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - // On short buffer error, function should return minimum buffer length - ASSERT_GT(dev_id_len, 0u); -} - -TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { - OEMCryptoResult sts; - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - sts = OEMCrypto_GetKeyData(key_data, &key_data_len); - - uint32_t* data = reinterpret_cast(key_data); - printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n", - htonl(data[1]), htonl(data[1]), htonl(data[0])); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); -} - -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForHugeIdLength) { - auto oemcrypto_function = [](size_t input_length) { - size_t key_data_length = input_length; - vector key_data(key_data_length); - return OEMCrypto_GetKeyData(key_data.data(), &key_data_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_F(OEMCryptoKeyboxTest, GetKeyDataNullPointer) { - OEMCryptoResult sts; - uint8_t key_data[256]; - sts = OEMCrypto_GetKeyData(key_data, nullptr); - ASSERT_NE(OEMCrypto_SUCCESS, sts); -} - -// This test makes sure the installed keybox is valid. It doesn't really check -// that it is a production keybox. That must be done by an integration test. -TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); -} - -// This tests GenerateDerivedKeys with an 8k context. -TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - const size_t max_size = GetResourceValue(kLargeMessageSize); - vector mac_context(max_size); - vector enc_context(max_size); - // Stripe the data so the two vectors are not identical, and not all zeroes. - for (size_t i = 0; i < max_size; i++) { - mac_context[i] = i % 0x100; - enc_context[i] = (3 * i) % 0x100; - } - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GenerateDerivedKeys( - s.session_id(), mac_context.data(), mac_context.size(), - enc_context.data(), enc_context.size())); -} - -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_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); -} - -// This class is for tests that have an OEM Certificate instead of a keybox. -class OEMCryptoProv30Test : public OEMCryptoClientTest {}; - -// This verifies that the device really does claim to have a certificate. -// It should be filtered out for devices that have a keybox. -TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) { - ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); -} - -TEST_F(OEMCryptoProv30Test, GetDeviceId) { - OEMCryptoResult sts; - std::vector dev_id(128, 0); - size_t dev_id_len = dev_id.size(); - sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); - if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - ASSERT_GT(dev_id_len, 0u); - dev_id.resize(dev_id_len); - sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - dev_id.resize(dev_id_len); - cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) - << " len = " << dev_id_len << endl; -} - -// The OEM certificate must be valid. -TEST_F(OEMCryptoProv30Test, CertValidAPI15) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxOrOEMCertValid()); -} - -TEST_F(OEMCryptoProv30Test, OEMCertValid) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - bool kVerify = true; - ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert(kVerify)); // Load and verify. -} - -/// @} - -/// @addtogroup license -/// @{ - -// This verifies that the OEM Certificate cannot be used for other RSA padding -// schemes. Those schemes should only be used by cast receiver certificates. -TEST_F(OEMCryptoProv30Test, OEMCertForbiddenPaddingScheme) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); - OEMCryptoResult sts; - // Sign a Message - vector data(500); - GetRandBytes(data.data(), data.size()); - size_t signature_length = 0; - // We need a size one vector to pass as a pointer. - vector signature(1, 0); - vector zero(1, 0); - - sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), data.size(), - signature.data(), &signature_length, - kSign_PKCS1_Block1); - if (OEMCrypto_ERROR_SHORT_BUFFER == sts) { - // The OEMCrypto could complain about buffer length first, so let's - // resize and check if it's writing to the signature again. - signature.resize(signature_length, 0); - zero.resize(signature_length, 0); - sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), - data.size(), signature.data(), - &signature_length, kSign_PKCS1_Block1); - } - EXPECT_NE(OEMCrypto_SUCCESS, sts) - << "OEM Cert Signed with forbidden kSign_PKCS1_Block1."; - ASSERT_EQ(zero, signature); // signature should not be computed. -} - -// Calling OEMCrypto_GetOEMPublicCertificate should not change the session's -// private key. -TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) { - if (wrapped_rsa_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(CreateWrappedRSAKey()); - } - 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.SetTestRsaPublicKey()); - // Request the OEM Cert. -- This should NOT load the OEM Private key. - vector public_cert; - size_t public_cert_length = 0; - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_GetOEMPublicCertificate(nullptr, &public_cert_length)); - ASSERT_LT(0u, public_cert_length); - public_cert.resize(public_cert_length); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetOEMPublicCertificate( - public_cert.data(), &public_cert_length)); - // Derive keys from the session key -- this should use the DRM Cert's key. It - // should NOT use the OEM Private key because that key should not have been - // loaded. - ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey()); - // Now fill a message and try to load it. - LicenseRoundTrip license_messages(&s); - license_messages.set_control(0); - 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()); -} - -TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { - if (wrapped_rsa_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(CreateWrappedRSAKey()); - } - 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.SetTestRsaPublicKey()); - - auto oemcrypto_function = [](size_t input_length) { - size_t public_cert_length = input_length; - vector public_cert(public_cert_length); - return OEMCrypto_GetOEMPublicCertificate(public_cert.data(), - &public_cert_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -// This class is for tests that have boot certificate chain instead of a keybox. -class OEMCryptoProv40Test : public OEMCryptoClientTest {}; - -// This verifies that the device really does claim to have BCC. -// It should be filtered out for devices that have a keybox or factory OEM cert. -TEST_F(OEMCryptoProv40Test, DeviceClaimsBootCertificateChain) { - ASSERT_EQ(OEMCrypto_GetProvisioningMethod(), OEMCrypto_BootCertificateChain); -} - -// Verifies that short buffer error returns when the buffer is short. -TEST_F(OEMCryptoProv40Test, GetBootCertificateChainShortBuffer) { - 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); - ASSERT_NE(bcc_size, 0uL); -} - -// Verifies BCC can be successfully returned. -TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) { - 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); -} - -// Verifies that short buffer error returns when the buffer is short. -TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairShortBuffer) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - std::vector public_key; - size_t public_key_size = 0; - std::vector public_key_signature; - size_t public_key_signature_size = 0; - std::vector wrapped_private_key; - size_t wrapped_private_key_size = 0; - OEMCrypto_PrivateKeyType key_type; - - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key.data(), &public_key_size, - public_key_signature.data(), &public_key_signature_size, - wrapped_private_key.data(), &wrapped_private_key_size, &key_type), - OEMCrypto_ERROR_SHORT_BUFFER); - - ASSERT_NE(public_key_size, 0uL); - ASSERT_NE(public_key_signature_size, 0uL); - ASSERT_NE(wrapped_private_key_size, 0uL); -} - -// Verifies a pair of key can be successfully returned. -TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairSuccess) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - std::vector public_key; - size_t public_key_size = 0; - std::vector public_key_signature; - size_t public_key_signature_size = 0; - std::vector wrapped_private_key; - size_t wrapped_private_key_size = 0; - OEMCrypto_PrivateKeyType key_type; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key.data(), &public_key_size, - public_key_signature.data(), &public_key_signature_size, - wrapped_private_key.data(), &wrapped_private_key_size, &key_type), - OEMCrypto_ERROR_SHORT_BUFFER); - public_key.resize(public_key_size); - public_key_signature.resize(public_key_signature_size); - wrapped_private_key.resize(wrapped_private_key_size); - - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key.data(), &public_key_size, - public_key_signature.data(), &public_key_signature_size, - wrapped_private_key.data(), &wrapped_private_key_size, &key_type), - OEMCrypto_SUCCESS); - public_key.resize(public_key_size); - public_key_signature.resize(public_key_signature_size); - wrapped_private_key.resize(wrapped_private_key_size); - // Parse the public key generated to make sure it is correctly formatted. - ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey( - key_type, public_key.data(), public_key_size)); -} - -// Verifies the generated key pairs are different on each call. -TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairsAreDifferent) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - // Large buffer to make sure it is large enough. - size_t public_key_size1 = 10000; - std::vector public_key1(public_key_size1); - size_t public_key_signature_size1 = 10000; - std::vector public_key_signature1(public_key_signature_size1); - size_t wrapped_private_key_size1 = 10000; - std::vector wrapped_private_key1(wrapped_private_key_size1); - OEMCrypto_PrivateKeyType key_type1; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key1.data(), &public_key_size1, - public_key_signature1.data(), &public_key_signature_size1, - wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), - OEMCrypto_SUCCESS); - EXPECT_NE(public_key_size1, 0UL); - EXPECT_NE(public_key_signature_size1, 0UL); - EXPECT_NE(wrapped_private_key_size1, 0UL); - public_key1.resize(public_key_size1); - public_key_signature1.resize(public_key_signature_size1); - wrapped_private_key1.resize(wrapped_private_key_size1); - - size_t public_key_size2 = 10000; - std::vector public_key2(public_key_size2); - size_t public_key_signature_size2 = 10000; - std::vector public_key_signature2(public_key_signature_size2); - size_t wrapped_private_key_size2 = 10000; - std::vector wrapped_private_key2(wrapped_private_key_size2); - OEMCrypto_PrivateKeyType key_type2; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key2.data(), &public_key_size2, - public_key_signature2.data(), &public_key_signature_size2, - wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), - OEMCrypto_SUCCESS); - EXPECT_NE(public_key_size2, 0UL); - EXPECT_NE(public_key_signature_size2, 0UL); - EXPECT_NE(wrapped_private_key_size2, 0UL); - public_key2.resize(public_key_size2); - public_key_signature2.resize(public_key_signature_size2); - wrapped_private_key2.resize(wrapped_private_key_size2); - - EXPECT_NE(public_key1, public_key2); - EXPECT_NE(public_key_signature1, public_key_signature2); - EXPECT_NE(wrapped_private_key1, wrapped_private_key2); -} - -// Verifies the an OEM private key can be installed. -TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeySuccess) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - // First generate a key pair. - // Large buffer to make sure it is large enough. - size_t public_key_size = 10000; - std::vector public_key(public_key_size); - size_t public_key_signature_size = 10000; - std::vector public_key_signature(public_key_signature_size); - size_t wrapped_private_key_size = 10000; - std::vector wrapped_private_key(wrapped_private_key_size); - OEMCrypto_PrivateKeyType key_type; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key.data(), &public_key_size, - public_key_signature.data(), &public_key_signature_size, - wrapped_private_key.data(), &wrapped_private_key_size, &key_type), - OEMCrypto_SUCCESS); - public_key.resize(public_key_size); - public_key_signature.resize(public_key_signature_size); - wrapped_private_key.resize(wrapped_private_key_size); - - // Install the generated private key. - ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, - wrapped_private_key.data(), - wrapped_private_key_size), - OEMCrypto_SUCCESS); -} - -// If data is empty or random, the API should return non-success status. -TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyInvalidDataFail) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - - // Empty key fails. - std::vector wrapped_private_key; - OEMCrypto_PrivateKeyType key_type = OEMCrypto_RSA_Private_Key; - ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, - wrapped_private_key.data(), - wrapped_private_key.size()), - OEMCrypto_SUCCESS); - - // Random key data fails. - wrapped_private_key = {1, 2, 3}; - ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, - wrapped_private_key.data(), - wrapped_private_key.size()), - OEMCrypto_SUCCESS); -} - -// Verifies the an OEM private key can be installed, and used by -// GenerateCertificateKeyPair call. -TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - // First generate a key pair. - size_t public_key_size1 = 10000; - std::vector public_key1(public_key_size1); - size_t public_key_signature_size1 = 10000; - std::vector public_key_signature1(public_key_signature_size1); - size_t wrapped_private_key_size1 = 10000; - std::vector wrapped_private_key1(wrapped_private_key_size1); - OEMCrypto_PrivateKeyType key_type1; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key1.data(), &public_key_size1, - public_key_signature1.data(), &public_key_signature_size1, - wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), - OEMCrypto_SUCCESS); - EXPECT_NE(public_key_size1, 0UL); - EXPECT_NE(public_key_signature_size1, 0UL); - EXPECT_NE(wrapped_private_key_size1, 0UL); - public_key1.resize(public_key_size1); - public_key_signature1.resize(public_key_signature_size1); - wrapped_private_key1.resize(wrapped_private_key_size1); - - // Install the generated private key. - ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type1, - wrapped_private_key1.data(), - wrapped_private_key_size1), - OEMCrypto_SUCCESS); - - // Now calling GenerateCertificateKeyPair should use wrapped_private_key to - // sign the newly generated public key. - size_t public_key_size2 = 10000; - std::vector public_key2(public_key_size2); - size_t public_key_signature_size2 = 10000; - std::vector public_key_signature2(public_key_signature_size2); - size_t wrapped_private_key_size2 = 10000; - std::vector wrapped_private_key2(wrapped_private_key_size2); - OEMCrypto_PrivateKeyType key_type2; - ASSERT_EQ( - OEMCrypto_GenerateCertificateKeyPair( - s.session_id(), public_key2.data(), &public_key_size2, - public_key_signature2.data(), &public_key_signature_size2, - wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), - OEMCrypto_SUCCESS); - EXPECT_NE(public_key_size2, 0UL); - EXPECT_NE(public_key_signature_size2, 0UL); - EXPECT_NE(wrapped_private_key_size2, 0UL); - public_key2.resize(public_key_size2); - public_key_signature2.resize(public_key_signature_size2); - wrapped_private_key2.resize(wrapped_private_key_size2); - - // Verify public_key_signature2 with public_key1. - if (key_type2 == 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) { - ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey( - public_key1.data(), public_key1.size())); - ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2, - public_key_signature2.data(), - public_key_signature2.size())); - } -} - -TEST_F(OEMCryptoProv40Test, GetDeviceId) { - OEMCryptoResult sts; - std::vector dev_id; - size_t dev_id_len = dev_id.size(); - sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); - if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - ASSERT_GT(dev_id_len, 0u); - dev_id.resize(dev_id_len); - sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - dev_id.resize(dev_id_len); - cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) - << " len = " << dev_id_len << endl; - // Device id should be stable. Query again. - std::vector dev_id2(dev_id_len); - sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(dev_id2, dev_id); -} - -// -// AddKey Tests -// -// These tests will use either a test keybox or a test certificate to derive -// session keys. -class OEMCryptoSessionTests : public OEMCryptoClientTest { - public: - vector encrypted_usage_header_; - - protected: - OEMCryptoSessionTests() {} - - void SetUp() override { - OEMCryptoClientTest::SetUp(); - EnsureTestKeys(); - if (global_features.usage_table) { - CreateUsageTableHeader(); - } - } - - void CreateUsageTableHeader(bool expect_success = true) { - size_t header_buffer_length = 0; - OEMCryptoResult sts = - OEMCrypto_CreateUsageTableHeader(nullptr, &header_buffer_length); - if (expect_success) { - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - } else { - ASSERT_NE(OEMCrypto_SUCCESS, sts); - if (sts != OEMCrypto_ERROR_SHORT_BUFFER) return; - } - encrypted_usage_header_.resize(header_buffer_length); - sts = OEMCrypto_CreateUsageTableHeader(encrypted_usage_header_.data(), - &header_buffer_length); - if (expect_success) { - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - encrypted_usage_header_.resize(header_buffer_length); - } else { - ASSERT_NE(OEMCrypto_SUCCESS, sts); - } - } - - void TestPrepareLicenseRequestForHugeBufferLengths( - const std::function f, - bool check_status) { - auto oemcrypto_function = [&](size_t message_length) { - Session s; - s.open(); - InstallTestRSAKey(&s); - LicenseRoundTrip license_messages(&s); - f(message_length, &license_messages); - OEMCryptoResult result = - license_messages.SignAndCreateRequestWithCustomBufferLengths(); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - OEMCryptoResult LoadLicense(Session& s, LicenseRoundTrip& license_messages) { - InstallTestRSAKey(&s); - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - license_messages.EncryptAndSignResponse(); - return license_messages.LoadResponse(); - } -}; - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryCreateUsageTableHeaderForHugeHeaderBufferLength) { - auto oemcrypto_function = [](size_t buffer_length) { - size_t header_buffer_length = buffer_length; - vector usage_table_header(header_buffer_length); - return OEMCrypto_CreateUsageTableHeader(usage_table_header.data(), - &header_buffer_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -class OEMCryptoSessionTestKeyboxTest : public OEMCryptoSessionTests {}; - -TEST_F(OEMCryptoSessionTestKeyboxTest, TestKeyboxIsValid) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); -} - -// This class is for testing a single license with the default API version -// of 16. -class OEMCryptoLicenseTestAPI16 : public OEMCryptoSessionTests { - public: - OEMCryptoLicenseTestAPI16() - : license_api_version_(kCurrentAPI), license_messages_(&session_) {} - - void SetUp() override { - OEMCryptoSessionTests::SetUp(); - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session_)); - } - - void TearDown() override { - ASSERT_NO_FATAL_FAILURE(session_.close()); - OEMCryptoSessionTests::TearDown(); - } - - protected: - Session session_; - uint32_t license_api_version_; - LicenseRoundTrip license_messages_; -}; - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryPrepareLicenseRequestForHugeRequestMessageLength) { - TestPrepareLicenseRequestForHugeBufferLengths( - [](size_t message_size, LicenseRoundTrip* license_messages) { - license_messages->set_message_size(message_size); - }, - kCheckStatus); -} - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryPrepareLicenseRequestForHugeCoreMessageLength) { - TestPrepareLicenseRequestForHugeBufferLengths( - [](size_t core_message_size, LicenseRoundTrip* license_messages) { - license_messages->set_core_message_size(core_message_size); - }, - kCheckStatus); -} - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryPrepareLicenseRequestForHugeSignatureLength) { - // There is a limit of signature length that gets validated. Hence not - // checking status as we would like to test it for all possible signature - // lengths. - TestPrepareLicenseRequestForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->set_request_signature_size(length); - }, - !kCheckStatus); -} - class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, public WithParamInterface { public: @@ -1709,7 +150,7 @@ class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, LicenseRoundTrip license_messages(&s); license_messages.set_api_version(license_api_version_); s.open(); - InstallTestRSAKey(&s); + InstallTestDrmKey(&s); bool verify_keys_loaded = true; license_messages.SignAndVerifyRequest(); license_messages.CreateDefaultResponse(); @@ -1742,7 +183,7 @@ class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, LicenseRoundTrip license_messages(&s); license_messages.set_api_version(license_api_version_); s.open(); - InstallTestRSAKey(&s); + InstallTestDrmKey(&s); license_messages.SignAndVerifyRequest(); license_messages.CreateDefaultResponse(); size_t message_length = sizeof(license_messages.response_data()); @@ -1819,245 +260,10 @@ class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { } }; -// This class is used to test a license that is from a server either that is -// current or one version old. -class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, - public WithParamInterface { - protected: - void SetUp() override { - // The only difference between this class and its parent is that we use a - // different license api: - license_api_version_ = GetParam(); - license_messages_.set_api_version(license_api_version_); - OEMCryptoLicenseTestAPI16::SetUp(); - } +/// @} - void LoadLicense() { - license_messages_.SignAndVerifyRequest(); - license_messages_.CreateDefaultResponse(); - license_messages_.EncryptAndSignResponse(); - license_messages_.LoadResponse(); - } - - void TestDecryptCENCForHugeBufferLengths( - const std::function f, - bool check_status) { - LoadLicense(); - auto oemcrypto_function = [&](size_t message_length) { - OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - - size_t input_buffer_size = 1; - vector in_buffer(input_buffer_size + message_length); - vector out_buffer(in_buffer.size()); - - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - GenerateSimpleSampleDescription( - in_buffer, out_buffer, &sample_description, &subsample_description); - - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description.subsamples); - // Actual tests modifies either of these fields to match clear + encrypted - // = in_buffer.size(). - sub_samples[0].num_bytes_clear = 0; - sub_samples[0].num_bytes_encrypted = input_buffer_size; - - // Create the pattern description (always 0,0 for CTR) - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - int secure_fd = 0; - f(message_length, &sample_description); - if (sample_description.buffers.output_descriptor.type == - OEMCrypto_BufferType_Secure) { - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_.session_id(), in_buffer.size(), - &sample_description.buffers.output_descriptor, &secure_fd); - if (sts != OEMCrypto_SUCCESS) { - LOGI("Secure buffers are not supported."); - return sts; - } - } - // Try to decrypt the data - OEMCryptoResult result = OEMCrypto_DecryptCENC( - session_.session_id(), &sample_description, 1, &pattern); - if (sample_description.buffers.output_descriptor.type == - OEMCrypto_BufferType_Secure) { - OEMCrypto_FreeSecureBuffer( - session_.session_id(), - &sample_description.buffers.output_descriptor, secure_fd); - } - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - void TestDecryptCENCForOutOfRangeOffsetsAndLengths( - const std::function f, - bool update_secure_buffer) { - LoadLicense(); - OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - - // Create the pattern description (always 0,0 for CTR) - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - int secure_fd = 0; - if (update_secure_buffer) { - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_.session_id(), in_buffer.size(), - &sample_description.buffers.output_descriptor, &secure_fd); - if (sts != OEMCrypto_SUCCESS) { - LOGI("Secure buffers are not supported."); - return; - } - } - f(&sample_description); - // Try to decrypt the data - OEMCryptoResult result = OEMCrypto_DecryptCENC( - session_.session_id(), &sample_description, 1, &pattern); - if (update_secure_buffer) { - OEMCrypto_FreeSecureBuffer(session_.session_id(), - &sample_description.buffers.output_descriptor, - secure_fd); - } - ASSERT_NE(OEMCrypto_SUCCESS, result); - } -}; - -// This class is used to test a license that is only for v15 license. -class OEMCryptoLicenseTestAPI15 : public OEMCryptoLicenseTestAPI16 { - void SetUp() override { - // The only difference between this class and its parent is that we use a - // different license api: - license_api_version_ = 15; - license_messages_.set_api_version(license_api_version_); - OEMCryptoLicenseTestAPI16::SetUp(); - } -}; - -// This class is used to test each key control block verification string in the -// range kc09-kc1?. This test is parameterized by the API number in the key -// control lock. -class OEMCryptoLicenseTestRangeAPI : public OEMCryptoLicenseTest {}; - -// Verify that a license may be signed. -TEST_P(OEMCryptoLicenseTest, SignLicenseRequest) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); -} - -// Verify that a large license request may be signed. -TEST_P(OEMCryptoLicenseTest, SignLargeLicenseRequest) { - const size_t max_size = GetResourceValue(kLargeMessageSize); - license_messages_.set_message_size(max_size); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); -} - -// Verify that a license may be loaded without a nonce. -TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonce) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(0); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); -} - -// Verify that a preloaded license may be loaded without first signing the -// request. This test is important for the preloaded licenses used by ATSC and -// CAS. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) { - if (license_api_version_ > global_features.api_version) { - // We should not attempt to preload a license with an API higher than that - // of OEMCrypto. - license_api_version_ = global_features.api_version; - license_messages_.set_api_version(license_api_version_); - } - license_messages_.set_control(0); - // Notice that we do not call SignAndVerifyRequest -- we do not need a request - // in order to generate a response for a preloaded license. - // The test code uses the core request to create the core response. - license_messages_.core_request().api_major_version = - global_features.api_version; - license_messages_.core_request().api_minor_version = 0; - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - - // Load license in a different session, which did not create the request. - Session session2; - ASSERT_NO_FATAL_FAILURE(session2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2)); - ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2)); - ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS)); -} - -// Verify that a license may be reloaded without a nonce, but with a nonzero -// rental duration. In order to start the rental clock, we sign a dummy license -// instead. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequestRentalDuration) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(0); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // It is not recommended for a license without a nonce to have a nonzero - // rental duration. But there are content providers that have licenses with - // this policy. - license_messages_.core_response().timer_limits.rental_duration_seconds = - kDuration; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - - // Load license in a different session, which did not create the request. - Session session2; - ASSERT_NO_FATAL_FAILURE(session2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2)); - // However, in order to start the rental clock, we have to sign something. So - // we will sign a dummy license request. - LicenseRoundTrip dummy_license(&session2); - ASSERT_NO_FATAL_FAILURE(dummy_license.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2)); - ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS)); -} - -// Verify that a license may be loaded with a nonce. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonce) { - 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()); - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); -} - -// Verify that a second license may not be loaded in a session. -TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonceTwiceAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(0); - license_messages_.skip_nonce_check(); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - // A second load, should NOT succeed. - ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); -} - -// Verify that a second license may not be loaded in a session. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) { - 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()); - // A second load, should NOT succeed. - ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); -} +/// @addtogroup entitle +/// @{ class OEMCryptoEntitlementLicenseTest : public OEMCryptoLicenseTest { protected: @@ -2070,13 +276,13 @@ class OEMCryptoEntitlementLicenseTest : public OEMCryptoLicenseTest { } }; -// This verifies that entitlement keys and entitled content keys can be loaded. +/** This verifies that entitlement keys and entitled content keys can be loaded. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); entitled_message_1.SetEntitledKeySession(key_session_id); @@ -2092,7 +298,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2113,19 +318,19 @@ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { /*load_even=*/false, /*load_odd=*/false, OEMCrypto_SUCCESS)); } -// This verifies that entitled content keys cannot be loaded if we have not yet -// loaded the entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have not yet + * loaded the entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2133,8 +338,10 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } -// This verifies that entitled content keys cannot be loaded if we have loaded -// the wrong entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have loaded + * the wrong entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); @@ -2144,7 +351,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2153,15 +359,16 @@ TEST_P(OEMCryptoEntitlementLicenseTest, /*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_CONTEXT)); } -// This verifies that entitled content keys cannot be loaded if we have loaded -// the wrong entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have loaded + * the wrong entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2177,7 +384,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2188,19 +394,21 @@ TEST_P(OEMCryptoEntitlementLicenseTest, /*load_even=*/true, /*load_odd=*/true, OEMCrypto_KEY_NOT_ENTITLED)); } -// This verifies that entitled content keys cannot be loaded if we specify an -// entitled key session that has not been created. +/** + * This verifies that entitled content keys cannot be loaded if we specify an + * entitled key session that has not been created. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysWrongEntitledKeySessionAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); - entitled_message_1.SetEntitledKeySession(0); + const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0; + entitled_message_1.SetEntitledKeySession(wrong_key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } @@ -2210,28 +418,34 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); - entitled_message_1.SetEntitledKeySession(0); + const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0; + entitled_message_1.SetEntitledKeySession(wrong_key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( /*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); } -// This verifies that entitled content keys cannot be loaded if we specify an -// entitled key session that is actually an oemcrypto session. +/** + * This verifies that entitled content keys cannot be loaded if we specify an + * entitled key session that is actually an oemcrypto session. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysOemcryptoSessionAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); + if (session_.session_id() == key_session_id) { + GTEST_SKIP() + << "Skipping test because entitled and entitlement sessions are both " + << key_session_id << "."; + } entitled_message_1.SetEntitledKeySession(session_.session_id()); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } @@ -2242,7 +456,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2255,35 +468,10 @@ TEST_P(OEMCryptoEntitlementLicenseTest, INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoEntitlementLicenseTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryPrepareRenewalRequestForHugeBufferLength) { - RenewalRoundTrip renewal_messages(&license_messages_); - auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { - renewal_messages.set_message_size(buffer_length); - return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} +/// @} -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryPrepareRenewalRequestForHugeSignatureLength) { - RenewalRoundTrip renewal_messages(&license_messages_); - auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { - renewal_messages.set_request_signature_size(buffer_length); - return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryPrepareRenewalRequestForHugeCoreMessageLength) { - RenewalRoundTrip renewal_messages(&license_messages_); - auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { - renewal_messages.set_core_message_size(buffer_length); - return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} +/// @addtogroup security +/// @{ TEST_F(OEMCryptoMemoryLicenseTest, OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { @@ -2465,569 +653,12 @@ TEST_F(OEMCryptoMemoryLicenseTest, !kCheckStatus); } -// This verifies that entitled content keys API does not crash for unreasonable -// input message buffer lengths. -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeBufferLength) { - auto oemcrypto_function = [&](size_t buffer_length) { - size_t entitled_key_data_length = - entitled_message_.entitled_key_data_size(); - vector message(entitled_key_data_length); - memcpy(message.data(), entitled_message_.entitled_key_data(), - entitled_key_data_length); - message.resize(buffer_length); - return entitled_message_.LoadKeys(message); - }; - // We are not constructing a valid message for load entitled content keys. - // Hence skipping status check. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -// This tests load license with an 8k license response. -TEST_P(OEMCryptoLicenseTest, LoadKeyLargeBuffer) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - const size_t max_size = GetResourceValue(kLargeMessageSize); - license_messages_.set_message_size(max_size); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// Verify that you can't use LoadKeys on a v16 license. -TEST_F(OEMCryptoLicenseTestAPI16, UseWrongLoadAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - // After the license round trip was create for v16, we now tell it to use v15 - // so it call LoadKeys instead of LoadLicense. This means the license request - // was made from a v16 device, and the response was created and signed by a - // v16 server. So OEMCrypto should only accept it if we load it using - // LoadLicense. A call to LoadKeys should fail. - license_messages_.set_api_version(kCoreMessagesAPI - 1); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -//---------------------------------------------------------------------------// -//---------------------------------------------------------------------------// -// Each of the following LoadKeyWithBadRange_* tests is similar. They verify -// that OEMCrypto_LoadLicense checks the range of all the pointers. It should -// reject a message if the pointer does not point into the message buffer. -//---------------------------------------------------------------------------// -//---------------------------------------------------------------------------// -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().enc_mac_keys.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys_iv) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().enc_mac_keys_iv.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_id) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().key_array[0].key_id.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().key_array[1].key_data.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data_iv) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().key_array[1].key_data_iv.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().key_array[2].key_control.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control_iv) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().key_array[2].key_control_iv.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_pst) { - license_messages_.set_control(wvoec::kControlNonceOrEntry); - license_messages_.set_pst("my_pst"); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // See the comment in LicenseRoundTrip::LoadResponse for why we increment by - // the message size. - license_messages_.core_response().pst.offset += - sizeof(license_messages_.response_data()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - // If we have a pst, then we need a usage entry. - ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} -//---------------------------------------------------------------------------// -//---------------------------------------------------------------------------// - -// The IV should not be identical to the data right before the encrypted mac -// keys. This requirement was added in 15.2, so it frequently fails on -// production devices. -// This test is being restricted to v16 devices on rvc-dev branch because we -// only required v15.1 on Android for Q. -TEST_F(OEMCryptoLicenseTestAPI15, LoadKeyWithSuspiciousIVAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - - // This is suspicious: the data right before the mac keys is identical to the - // iv. - memcpy(license_messages_.response_data().padding, - license_messages_.response_data().mac_key_iv, - sizeof(license_messages_.response_data().padding)); - - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// Test that LoadKeys fails when a key is loaded with no key control block. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNullKeyControl) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_response().key_array[2].key_control.offset = 0; - license_messages_.core_response().key_array[2].key_control.length = 0; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// Verify that LoadKeys fails when a key's nonce is wrong. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadNonce) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - for (unsigned int i = 0; i < license_messages_.num_keys(); i++) - license_messages_.response_data().keys[i].control.nonce ^= 42; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// Verify that LoadKeys fails when the core message's nonce is wrong. -TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce2) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_request().nonce ^= 42; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// Verify that LoadKeys fails when the core message's session is wrong. -TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce3) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_request().session_id++; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// Verify that LoadKeys fails when an attempt is made to use a nonce twice. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithRepeatNonce) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - const uint32_t nonce = session_.nonce(); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - // This is the first attempt. It should succeed. - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - - // Now, open a new session and try to load a license with the same nonce. - session_.close(); - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session_)); - license_messages_.skip_nonce_check(); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - // Repeat the nonce. - license_messages_.core_request().nonce = nonce; - for (unsigned int i = 0; i < license_messages_.num_keys(); i++) - license_messages_.response_data().keys[i].control.nonce = htonl(nonce); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// This tests that a nonce cannot be used in new session. This is similar to -// the previous test, but does not use the nonce in the first session. The nonce -// should be tied to a session, so generating a nonce in the first session and -// then using it in the second session should fail. -TEST_P(OEMCryptoLicenseTest, LoadKeyNonceReopenSession) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); - uint32_t nonce = session_.nonce(); - // Do not use the nonce now. Close session and use it after re-opening. - ASSERT_NO_FATAL_FAILURE(session_.close()); - - // Actually, this isn't the same session. OEMCrypto opens a new session, but - // we are guarding against the possiblity that it re-uses the session data - // and might not clear out the nonce correctly. - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session_)); - license_messages_.skip_nonce_check(); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_request().nonce = nonce; - for (unsigned int i = 0; i < license_messages_.num_keys(); i++) - license_messages_.response_data().keys[i].control.nonce = htonl(nonce); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// This tests that a nonce cannot be used in wrong session. This is similar to -// the previous test, except we do not close session 1 before we open session 2. -TEST_P(OEMCryptoLicenseTest, LoadKeyNonceWrongSession) { - // First, open a session and generate a nonce. We don't use the nonce in this - // session. - Session s2; - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s2)); - ASSERT_NO_FATAL_FAILURE(s2.GenerateNonce()); - uint32_t nonce = s2.nonce(); - - // Do not use the nonce. Also, leave the session open. We want to make sure - // that session_ and s2 do NOT share a nonce. This is different from - // the LoadKeyNonceReopenSession in that we do not close s1. - - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_request().nonce = nonce; - for (unsigned int i = 0; i < license_messages_.num_keys(); i++) - license_messages_.response_data().keys[i].control.nonce = htonl(nonce); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse()); -} - -// LoadKeys should fail if the key control block as a bad verification string. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadVerification) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.response_data().keys[1].control.verification[2] = 'Z'; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// This test verifies that LoadKeys still works when the message is not aligned -// in memory on a word (2 or 4 byte) boundary. -TEST_P(OEMCryptoLicenseTest, LoadKeyUnalignedMessageAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - - std::vector buffer(1, '0'); // A string of 1 byte long. - size_t offset = buffer.size(); - ASSERT_EQ(1u, offset); - // We assume that vectors are allocated on as a small chunk of data that is - // aligned on a word boundary. I.e. we assume buffer is word aligned. Next, - // we append the message to buffer after the single padding byte. - buffer.insert(buffer.end(), - license_messages_.encrypted_response_buffer().begin(), - license_messages_.encrypted_response_buffer().end()); - // Thus, buffer[offset] is NOT word aligned. - const uint8_t* unaligned_message = &buffer[offset]; - if (license_api_version_ < kCoreMessagesAPI) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys( - session_.session_id(), unaligned_message, - license_messages_.encrypted_response_buffer().size(), - license_messages_.response_signature().data(), - license_messages_.response_signature().size(), - license_messages_.core_response().enc_mac_keys_iv, - license_messages_.core_response().enc_mac_keys, - license_messages_.core_response().key_array_length, - license_messages_.core_response().key_array, - license_messages_.core_response().pst, - license_messages_.core_response().srm_restriction_data, - static_cast( - license_messages_.core_response().license_type))); - } else { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadLicense( - session_.session_id(), unaligned_message, - license_messages_.encrypted_response_buffer().size(), - license_messages_.serialized_core_message().size(), - license_messages_.response_signature().data(), - license_messages_.response_signature().size())); - } -} - -// Verifies that a session can't reload a license without being closed and -// reopened. -TEST_P(OEMCryptoLicenseTest, LoadLicenseAgainFailureAPI16) { - 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()); - ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); -} - -TEST_P(OEMCryptoLicenseTestRangeAPI, LoadKeys) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - // Re-set the API version. The function VerifyRequestSignature sets the api to - // be a sane value. But in this test, we want to verify an unsupported version - // is rejected. - license_messages_.set_api_version(license_api_version_); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - - // If this is a future API, then LoadKeys should fail. - if (global_features.api_version < license_api_version_) { - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()) - << "Load License succeeded for future api kc" << license_api_version_; - } else { - // Otherwise, LoadKeys should succeed. - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()) - << "Load License failed for key control block kc" - << license_api_version_; - } -} - -// Range of API versions to test. This should start several versions old, and -// go to the current API + 2. We use +2 because we want to test at least 1 -// future API, and the ::testing::Range is not inclusive. -INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTestRangeAPI, - Range(10, kCurrentAPI + 2)); - -TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - license_messages_.response_signature()[0] ^= 42; - ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, - license_messages_.LoadResponse()); -} /// @} -/// @addtogroup decrypt +/// @addtogroup entitle /// @{ -// LoadKeys should fail if we try to load keys with no keys. -TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeys) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(0); - license_messages_.set_num_keys(0); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// Like the previous test, except we ask for a nonce first. -TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeyWithNonce) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_num_keys(0); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - -// Following two tests will test huge values for num bytes clear, num bytes -// encrypted, input data length and clear address, clear address_length. -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForHugeNumBytesClearAndBuffers) { - TestDecryptCENCForHugeBufferLengths( - [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description->subsamples); - sub_samples[0].num_bytes_clear = - sub_samples[0].num_bytes_clear + message_size; - }, - !kCheckStatus); -} - -TEST_P(OEMCryptoLicenseTest, - DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) { - LoadLicense(); - OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CENC); - - size_t input_buffer_size = 1; - vector in_buffer(input_buffer_size); - vector out_buffer(in_buffer.size()); - - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description.subsamples); - // If Decrypt cenc API does not check for overflow on clear + encrypted - // addition operation. This will result in 1 which will match with input data - // length, which causes validation to pass. - sub_samples[0].num_bytes_clear = 2; - sub_samples[0].num_bytes_encrypted = ~0; - - // Create the pattern description (always 0,0 for CTR) - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - // Try to decrypt the data - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern)); -} - -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) { - TestDecryptCENCForHugeBufferLengths( - [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description->subsamples); - sub_samples[0].num_bytes_encrypted = - sub_samples[0].num_bytes_encrypted + message_size; - }, - !kCheckStatus); -} - -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForHugeSecureHandleLength) { - TestDecryptCENCForHugeBufferLengths( - [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description->subsamples); - // TestDecryptCENCForHugeBufferLengths alloctes huge secure handle - // buffer. - sample_description->buffers.output_descriptor.type = - OEMCrypto_BufferType_Secure; - sub_samples[0].num_bytes_clear = - sub_samples[0].num_bytes_clear + message_size; - }, - !kCheckStatus); -} - -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesClear) { - TestDecryptCENCForOutOfRangeOffsetsAndLengths( - [](OEMCrypto_SampleDescription* sample_description) { - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description->subsamples); - sub_samples[0].num_bytes_clear = sub_samples[0].num_bytes_clear + 1; - }, - !kDecryptCENCSecureBuffer); -} - -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesEncryptedAPI16) { - TestDecryptCENCForOutOfRangeOffsetsAndLengths( - [](OEMCrypto_SampleDescription* sample_description) { - OEMCrypto_SubSampleDescription* sub_samples = - const_cast( - sample_description->subsamples); - sub_samples[0].num_bytes_encrypted = - sub_samples[0].num_bytes_encrypted + 1; - }, - !kDecryptCENCSecureBuffer); -} - -TEST_P(OEMCryptoLicenseTest, - OEMCryptoMemoryDecryptCENCForOutOfRangeSecureBufferOffset) { - TestDecryptCENCForOutOfRangeOffsetsAndLengths( - [](OEMCrypto_SampleDescription* sample_description) { - sample_description->buffers.output_descriptor.type = - OEMCrypto_BufferType_Secure; - sample_description->buffers.output_descriptor.buffer.secure.offset = - sample_description->buffers.output_descriptor.buffer.secure - .secure_buffer_length + - 1; - }, - kDecryptCENCSecureBuffer); -} - -// Cannot decrypt without first selecting a key. -TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutSelect) { - 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()); - ASSERT_NO_FATAL_FAILURE( - session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// SelectKey should fail if we attempt to select a key that has not been loaded. -// Also, the error should be NO_CONTENT_KEY. -// This test should pass for v15 devices, except that the exact error code was -// not specified until v16. -TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI16) { - 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()); - - const char* key_id = "no_key"; - OEMCryptoResult sts = OEMCrypto_SelectKey( - session_.session_id(), reinterpret_cast(key_id), - strlen(key_id), OEMCrypto_CipherMode_CENC); - if (sts != OEMCrypto_SUCCESS) { - EXPECT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, sts); - } else { - // Delayed error code. If select key was a success, then we should - // eventually see the error when we decrypt. - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - - // Generate test data - for (size_t i = 0; i < in_buffer.size(); i++) in_buffer[i] = i % 256; - - // Create the pattern description (always 0,0 for CTR) - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - - // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_EQ(sts, OEMCrypto_ERROR_NO_CONTENT_KEY); - } -} - -TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyAPI17) { +TEST_P(OEMCryptoLicenseTest, GetKeyHandleEntitledKeyAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); @@ -3044,11 +675,12 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyAPI17) { entitled_message_1.SetContentKeyId(0, content_key_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id), - strlen(content_key_id), OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector( + key_session_id, reinterpret_cast(content_key_id), + strlen(content_key_id), OEMCrypto_CipherMode_CENC, key_handle)); } // SelectEntitledKey should fail if we attempt to select a key that has not been @@ -3069,15 +701,16 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyNotThereAPI17) { ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); const char* content_key_id = "no_key"; - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id), - strlen(content_key_id), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_INVALID_CONTEXT, key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id))); } -// Select key with entitlement license fails if the key id is entitlement key -// id. +/** + * Select key with entitlement license fails if the key id is entitlement key + * id. + */ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -3093,11 +726,15 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) { entitled_message_1.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); - OEMCryptoResult res = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - EXPECT_TRUE(res == OEMCrypto_ERROR_INVALID_CONTEXT || - res == OEMCrypto_ERROR_NO_CONTENT_KEY); + if (session_.session_id() == key_session_id) { + GTEST_SKIP() + << "Skipping test because entitled and entitlement sessions are both " + << key_session_id << "."; + } + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_INVALID_CONTEXT, session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length)); } // This verifies that entitled key sessions can be created and removed. @@ -3126,6 +763,27 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionsAPI17) { OEMCrypto_RemoveEntitledKeySession(key_session_id_2)); } +TEST_P(OEMCryptoLicenseTest, + EntitledKeySessionsCloseWithOEMCryptoSessionAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id_1; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_1)); + // Close the OEMCrypto session. + session_.close(); + // All entitled key sessions associated with the OEMCrypto session should + // already be destroyed. + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_RemoveEntitledKeySession(key_session_id_1)); + // Open a new session just for OEMCryptoLicenseTest TearDown. + session_.open(); +} + // This verifies that multiple entitled key sessions can be created. They can // load and select keys independently. TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { @@ -3145,15 +803,24 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { entitled_message_1.SetContentKeyId(0, content_key_id_1); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 1 in entitled key session 1. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id_1, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id_1, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Create another entitled key session. uint32_t key_session_id_2; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( - session_.session_id(), &key_session_id_2)); + OEMCryptoResult status = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_2); + // For DRM, but not for CAS, we allow there to be only a single entitled + // session. + if (!global_features.supports_cas && + (key_session_id_2 == key_session_id_1 || + status == OEMCrypto_ERROR_TOO_MANY_SESSIONS)) { + GTEST_SKIP() + << "Skipping test because multiple entitled sessions not supported."; + } + ASSERT_EQ(OEMCrypto_SUCCESS, status); // Entitled key sessions should have unique ids. ASSERT_NE(key_session_id_1, key_session_id_2); @@ -3164,23 +831,22 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { entitled_message_2.SetContentKeyId(0, content_key_id_2); ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(true)); // We can select content key 2 in entitled key session 2. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id_2, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id_2, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); + // Content key id 1 is not in entitled key session 2. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id_2, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_2, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Content key id 2 is not in entitled key session 1. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id_1, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_1, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); } // This verifies that within an entitled key session, each entitlement key can @@ -3204,32 +870,31 @@ TEST_P(OEMCryptoLicenseTest, entitled_message_1.SetContentKeyId(0, content_key_id_1); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 1 in entitled key session. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Load content key with new content id. const char* content_key_id_2 = "content_key_id_2"; entitled_message_1.SetContentKeyId(0, content_key_id_2); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 2 in entitled key session. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); + // Content key one is no longer in the entitled key session as they use the // same entitlement key. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); } -// Decrypt should fail if the license is entitlement license, and the decrypt -// call is made with oemcrypto session id (should use entitled key session id +// Decrypt should fail if the license is entitlement license, and the key handle +// is requested from the oemcrypto session (should use entitled key session id // instead). TEST_P(OEMCryptoLicenseTest, RejectOecSessionDecryptWithEntitlementLicenseAPI17) { @@ -3242,35 +907,31 @@ TEST_P(OEMCryptoLicenseTest, uint32_t key_session_id; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - // Construct and load content keys to entitled key session. - EntitledMessage entitled_message(&license_messages_); - entitled_message.FillKeyArray(); - entitled_message.SetEntitledKeySession(key_session_id); - const char* content_key_id = "content_key_id"; - entitled_message.SetContentKeyId(0, content_key_id); - ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id), - strlen(content_key_id), OEMCrypto_CipherMode_CENC)); - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - in_buffer, out_buffer, &sample_description, &subsample_description)); - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + // Skip the rest of this test on platforms that do not support separate + // entitlement and entitled sessions. + if (global_features.supports_cas || session_.session_id() != key_session_id) { + // Construct and load content keys to entitled key session. + EntitledMessage entitled_message(&license_messages_); + entitled_message.FillKeyArray(); + entitled_message.SetEntitledKeySession(key_session_id); + constexpr char kContentKeyId[] = "content_key_id"; + const size_t content_key_id_length = strlen(kContentKeyId); + entitled_message.SetContentKeyId(0, kContentKeyId); + ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(kContentKeyId), + content_key_id_length)); - // Try to decrypt the data with oemcrypto session id. - EXPECT_EQ(OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern), - OEMCrypto_ERROR_INVALID_CONTEXT); - // Decrypt the data with entitled key session id succeed. - EXPECT_EQ( - OEMCrypto_DecryptCENC(key_session_id, &sample_description, 1, &pattern), - OEMCrypto_SUCCESS); + // Try to get a key handle with the oemcrypto session id. + vector key_handle; + EXPECT_NE(GetKeyHandleIntoVector( + session_.session_id(), + reinterpret_cast(kContentKeyId), + content_key_id_length, OEMCrypto_CipherMode_CENC, key_handle), + OEMCrypto_SUCCESS); + } } // This verifies that an entitled key session can be reassociated to an @@ -3284,7 +945,7 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { // Setup another session. Session session2; ASSERT_NO_FATAL_FAILURE(session2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2)); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session2)); ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); // Setup an entitled key session in the first OEMCrypto session. uint32_t key_session_id; @@ -3297,8 +958,14 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); // Now reassociate the entitled key session to the second OEMCrypto session. - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ReassociateEntitledKeySession( - key_session_id, session2.session_id())); + OEMCryptoResult status = OEMCrypto_ReassociateEntitledKeySession( + key_session_id, session2.session_id()); + if (status == OEMCrypto_ERROR_NOT_IMPLEMENTED && + !global_features.supports_cas) { + GTEST_SKIP() << "Skipping test because " + "OEMCrypto_ReassociateEntitledKeySession not implemented."; + } + ASSERT_EQ(OEMCrypto_SUCCESS, status); // session2 does not have entitlement keys. ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(false)); @@ -3309,214 +976,10 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); } -// 'cens' mode is no longer supported in v16 -TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) { - 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()); +/// @} - OEMCryptoResult sts; - sts = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - - // Create a non-zero pattern to indicate this is 'cens' - OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; - - // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); -} - -// 'cbc1' mode is no longer supported in v16 -TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) { - 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()); - - OEMCryptoResult sts; - sts = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBCS); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - - // Create a zero pattern to indicate this is 'cbc1' - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - - // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); -} - -TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { - 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()); - - OEMCryptoResult sts; - sts = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBCS); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - subsample_description.block_offset = 5; // Any value 1-15 will do. - - // Create a non-zero pattern to indicate this is 'cbcs'. - OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; - - // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); -} - -TEST_P(OEMCryptoLicenseTest, RejectOversizedBlockOffset) { - 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()); - - OEMCryptoResult sts; - sts = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - - vector in_buffer(256); - vector out_buffer(in_buffer.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, - &subsample_description); - subsample_description.block_offset = 0xFF; // Anything 16+ - - // Create a zero pattern to indicate this is 'cenc'. - OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - - // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_NE(OEMCrypto_SUCCESS, sts); - - // Try again with the minimum invalid value - subsample_description.block_offset = 16; - sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern); - EXPECT_NE(OEMCrypto_SUCCESS, sts); -} - -// After loading keys, we should be able to query the key control block. If we -// attempt to query a key that has not been loaded, the error should be -// NO_CONTENT_KEY. -TEST_P(OEMCryptoLicenseTest, QueryKeyControl) { - 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()); - - // Note: successful cases are tested in VerifyTestKeys. - KeyControlBlock block; - size_t size = sizeof(block) - 1; - OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - session_.session_id(), license_messages_.response_data().keys[0].key_id, - license_messages_.response_data().keys[0].key_id_length, - reinterpret_cast(&block), &size); - if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { - return; - } - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - const char* key_id = "no_key"; - size = sizeof(block); - ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_QueryKeyControl( - session_.session_id(), reinterpret_cast(key_id), - strlen(key_id), reinterpret_cast(&block), &size)); -} - -// This case tests against the issue where certain 16.4.x SDK versions return a -// clear key control block (KCB) in the license response. An OEMCrypto v17.1+ -// implementation should be able to handle the clear KCB in the 16.4.x response -// and load the license correctly. -TEST_F(OEMCryptoSessionTests, ClearKcbAPI16_4) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - // Set odk version in the license response to be 16.4 - oemcrypto_core_message::features::CoreMessageFeatures features = {}; - features.maximum_major_version = 16; - features.maximum_minor_version = 4; - constexpr bool kForceClearKcb = true; - ASSERT_NO_FATAL_FAILURE( - license_messages.EncryptAndSignResponseWithCoreMessageFeatures( - features, kForceClearKcb)); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); - - KeyControlBlock block; - size_t size = sizeof(block); - OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - s.session_id(), license_messages.response_data().keys[0].key_id, - license_messages.response_data().keys[0].key_id_length, - reinterpret_cast(&block), &size); - if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { - return; - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); -} - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryLoadLicenseForHugeSignatureLength) { - auto oemcrypto_function = [&](size_t signature_size) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - InstallTestRSAKey(&s); - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - license_messages.EncryptAndSignResponse(); - vector signature(signature_size); - OEMCryptoResult result = OEMCrypto_LoadLicense( - s.session_id(), license_messages.encrypted_response_buffer().data(), - license_messages.encrypted_response_buffer().size(), - license_messages.serialized_core_message().size(), signature.data(), - signature_size); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} +/// @addtogroup security +/// @{ TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { @@ -3838,7 +1301,8 @@ TEST_P(OEMCryptoLicenseOverflowTest, TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { auto& pst = license_messages->core_response().pst; - pst.offset = response_message_length - pst.length + 1; + pst.offset = response_message_length; + if (pst.length == 0) pst.length = 1; }); } @@ -3881,8 +1345,8 @@ TEST_P( [](size_t response_message_length, LicenseRoundTrip* license_messages) { auto& srm_restriction_data = license_messages->core_response().srm_restriction_data; - srm_restriction_data.offset = - response_message_length - srm_restriction_data.length + 1; + srm_restriction_data.offset = response_message_length; + if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; }); } @@ -3907,311 +1371,10 @@ TEST_P(OEMCryptoLicenseOverflowTest, INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, Range(kCurrentAPI - 1, kCurrentAPI + 1)); -TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadRenewalForHugeResponseLength) { - auto oemcrypto_function = [&](size_t message_size) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - LoadLicense(s, license_messages); +/// @} - RenewalRoundTrip renewal_messages(&license_messages); - renewal_messages.SignAndVerifyRequest(); - renewal_messages.CreateDefaultResponse(); - renewal_messages.set_message_size(message_size); - renewal_messages.EncryptAndSignResponse(); - OEMCryptoResult result = renewal_messages.LoadResponse(); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryLoadRenewalForHugeSignatureLength) { - auto oemcrypto_function = [&](size_t signature_size) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - LoadLicense(s, license_messages); - - RenewalRoundTrip renewal_messages(&license_messages); - renewal_messages.SignAndVerifyRequest(); - renewal_messages.CreateDefaultResponse(); - renewal_messages.EncryptAndSignResponse(); - vector signature(signature_size); - OEMCryptoResult result = OEMCrypto_LoadRenewal( - s.session_id(), renewal_messages.encrypted_response_buffer().data(), - renewal_messages.encrypted_response_buffer().size(), - renewal_messages.serialized_core_message().size(), signature.data(), - signature_size); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryLoadRenewalForHugeCoreMessageLength) { - auto oemcrypto_function = [&](size_t core_message_size) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - LoadLicense(s, license_messages); - - RenewalRoundTrip renewal_messages(&license_messages); - renewal_messages.SignAndVerifyRequest(); - renewal_messages.CreateDefaultResponse(); - renewal_messages.set_core_message_size(core_message_size); - renewal_messages.EncryptAndSignResponse(); - OEMCryptoResult result = renewal_messages.LoadResponse(); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { - Session session; - LicenseRoundTrip license_messages(&session); - session.open(); - LoadLicense(session, license_messages); - OEMCrypto_SESSION session_id = session.session_id(); - vector valid_key_id( - license_messages.response_data().keys[0].key_id, - license_messages.response_data().keys[0].key_id + kTestKeyIdMaxLength); - auto oemcrypto_function = [&session_id, - &valid_key_id](size_t additional_key_id_length) { - vector key_id(valid_key_id); - key_id.resize(valid_key_id.size() + additional_key_id_length); - KeyControlBlock block; - size_t size = sizeof(block); - return OEMCrypto_QueryKeyControl(session_id, key_id.data(), key_id.size(), - reinterpret_cast(&block), &size); - }; - // We do not want to stop as soon as API results in an error as it would - // return error on first iteration as key_id is invalid. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_control_block -// length. -TEST_F(OEMCryptoSessionTests, - OEMCryptoMemoryQueryKeyControlForHugeKeyControlBlockLength) { - Session session; - LicenseRoundTrip license_messages(&session); - session.open(); - LoadLicense(session, license_messages); - OEMCrypto_SESSION session_id = session.session_id(); - uint8_t* key_id = license_messages.response_data().keys[0].key_id; - size_t key_id_length = license_messages.response_data().keys[0].key_id_length; - auto oemcrypto_function = [&session_id, &key_id, - &key_id_length](size_t buffer_length) { - size_t key_control_block_length = buffer_length; - vector key_control_block(key_control_block_length); - return OEMCrypto_QueryKeyControl(session_id, key_id, key_id_length, - key_control_block.data(), - &key_control_block_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -// If the device says it supports anti-rollback in the hardware, then it should -// accept a key control block with the anti-rollback hardware bit set. -// Otherwise, it should reject that key control block. -TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(wvoec::kControlRequireAntiRollbackHardware); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - OEMCryptoResult sts = license_messages_.LoadResponse(); - if (OEMCrypto_IsAntiRollbackHwPresent()) { - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - } else { - ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, sts); - } -} - -// This test verifies that OEMCrypto can load the number of keys required for -// the reported resource level. -TEST_P(OEMCryptoLicenseTest, MinimumKeys) { - const size_t num_keys = GetResourceValue(kMaxKeysPerSession); - ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; - license_messages_.set_num_keys(static_cast(num_keys)); - 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()); - - constexpr bool kSelectKeyFirst = true; - for (size_t key_index = 0; key_index < num_keys; key_index++) { - ASSERT_NO_FATAL_FAILURE( - session_.TestDecryptCTR(kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); - } -} - -// This test verifies that OEMCrypto can load the total number of keys required -// for the reported resource level. -void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) { - const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); - ASSERT_LE(num_keys_per_session, kMaxNumKeys) << "Update test constants."; - std::vector> sessions; - std::vector> licenses; - size_t total_keys = 0; - for (size_t i = 0; total_keys < max_total_keys; i++) { - sessions.push_back(std::unique_ptr(new Session())); - licenses.push_back(std::unique_ptr( - new LicenseRoundTrip(sessions[i].get()))); - const size_t num_keys = - std::min(max_total_keys - total_keys, num_keys_per_session); - licenses[i]->set_num_keys(static_cast(num_keys)); - total_keys += num_keys; - ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); - ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(sessions[i].get())); - ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest()); - } - for (size_t i = 0; i < licenses.size(); i++) { - ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse()); - } - constexpr bool kSelectKeyFirst = true; - for (size_t i = 0; i < licenses.size(); i++) { - for (size_t key_index = 0; key_index < licenses[i]->num_keys(); - key_index++) { - ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( - kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); - } - } - // Second call to decrypt for each session. - for (size_t i = 0; i < licenses.size(); i++) { - for (size_t key_index = 0; key_index < licenses[i]->num_keys(); - key_index++) { - ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( - kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); - } - } -} - -// This test verifies that OEMCrypto can load the total number of keys required -// for the reported resource level. This maximizes keys per session. -TEST_P(OEMCryptoLicenseTest, MaxTotalKeysPerSession) { - const size_t max_num_keys = GetResourceValue(kMaxKeysPerSession); - TestMaxKeys(this, max_num_keys); -} - -// This test verifies that OEMCrypto can load the total number of keys required -// for the reported resource level. This maximizes number of sessions. -TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) { - const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); - const size_t max_sessions = GetResourceValue(kMaxConcurrentSession); - const size_t max_num_keys = max_total_keys / max_sessions + 1; - TestMaxKeys(this, max_num_keys); -} - -// This test verifies that the minimum patch level can be required. The device -// should accept a key control block with the current patch level, and it should -// reject any key control blocks with a future patch level. -TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { - uint8_t patch_level = OEMCrypto_Security_Patch_Level(); - printf(" Current Patch Level: %u.\n", patch_level); - { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_control(patch_level - << wvoec::kControlSecurityPatchLevelShift); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - EXPECT_EQ(global_features.api_version, license_messages.api_version()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); - } - // Reject any future patch levels. - if (patch_level < 0x3F) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_control((patch_level + 1) - << wvoec::kControlSecurityPatchLevelShift); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, license_messages.LoadResponse()); - } - // Accept an old patch level. - if (patch_level > 0) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_control((patch_level - 1) - << wvoec::kControlSecurityPatchLevelShift); - 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()); - } -} - -// Used to test the different HDCP versions. This test is parameterized by the -// required HDCP version in the key control block. -class OEMCryptoSessionTestDecryptWithHDCP : public OEMCryptoSessionTests, - public WithParamInterface { - protected: - void DecryptWithHDCP(OEMCrypto_HDCP_Capability version) { - OEMCryptoResult sts; - OEMCrypto_HDCP_Capability current, maximum; - sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_control((version << wvoec::kControlHDCPVersionShift) | - wvoec::kControlObserveHDCP | - wvoec::kControlHDCPRequired); - 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()); - - if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) || - (current == HDCP_V1 && version >= HDCP_V1_0)) { - if (global_features.api_version >= 16) { - // Can provide either OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION or - // OEMCrypto_ERROR_INSUFFICIENT_HDCP. TestDecryptCTR allows either to be - // reported if OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION is expected. - ASSERT_NO_FATAL_FAILURE( - s.TestDecryptCTR(true, OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION)) - << "Failed when current HDCP = " << HDCPCapabilityAsString(current) - << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) - << ", license HDCP = " << HDCPCapabilityAsString(version); - } else { - ASSERT_NO_FATAL_FAILURE( - s.TestDecryptCTR(true, OEMCrypto_ERROR_INSUFFICIENT_HDCP)) - << "Failed when current HDCP = " << HDCPCapabilityAsString(current) - << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) - << ", license HDCP = " << HDCPCapabilityAsString(version); - } - } else { - ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(true, OEMCrypto_SUCCESS)) - << "Failed when current HDCP = " << HDCPCapabilityAsString(current) - << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) - << ", license HDCP = " << HDCPCapabilityAsString(version); - } - } -}; - -TEST_P(OEMCryptoSessionTestDecryptWithHDCP, DecryptAPI09) { - // Test parameterized by HDCP version. - DecryptWithHDCP(static_cast(GetParam())); -} -INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, - Range(1, 6)); +/// @addtogroup cas +/// @{ // Used to test the different HDCP versions. This test is parameterized by the // required HDCP version in the key control block. @@ -4225,7 +1388,7 @@ class OEMCryptoSessionTestLoadCasKeysWithHDCP : public OEMCryptoSessionTests, ASSERT_EQ(OEMCrypto_SUCCESS, sts); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); LicenseRoundTrip license_messages(&s); license_messages.set_control((version << wvoec::kControlHDCPVersionShift) | wvoec::kControlObserveHDCP | @@ -4275,47 +1438,6 @@ INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP, // // Load, Refresh Keys Test // -class OEMCryptoRefreshTest : public OEMCryptoLicenseTest { - protected: - void SetUp() override { - OEMCryptoLicenseTest::SetUp(); - // These values allow us to run a few simple duration tests or just start - // playback right away. All times are in seconds since the license was - // signed. - // Soft expiry false means timers are strictly enforce. - timer_limits_.soft_enforce_rental_duration = true; - timer_limits_.soft_enforce_playback_duration = false; - // Playback may begin immediately. - timer_limits_.earliest_playback_start_seconds = 0; - // First playback may be within the first two seconds. - timer_limits_.rental_duration_seconds = kDuration; - // Once started, playback may last two seconds without a renewal. - timer_limits_.initial_renewal_duration_seconds = kDuration; - // Total playback is not limited. - timer_limits_.total_playback_duration_seconds = 0; - } - - void LoadLicense() { - license_messages_.core_response().timer_limits = timer_limits_; - 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 MakeRenewalRequest(RenewalRoundTrip* renewal_messages) { - ASSERT_NO_FATAL_FAILURE(renewal_messages->SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(renewal_messages->CreateDefaultResponse()); - } - - void LoadRenewal(RenewalRoundTrip* renewal_messages, - OEMCryptoResult expected_result) { - ASSERT_NO_FATAL_FAILURE(renewal_messages->EncryptAndSignResponse()); - ASSERT_EQ(expected_result, renewal_messages->LoadResponse()); - } - - ODK_TimerLimits timer_limits_; -}; // This class is for the refresh tests that should only be run on licenses with // a core message. @@ -4418,6 +1540,62 @@ TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) { ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false)); } +// Test that playback clock is correctly started and that the license can be +// renewed. +TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadSuccess) { + license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load; + timer_limits_.rental_duration_seconds = kDuration; // 2 seconds. + timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds. + // First version to support Renew on Load. + constexpr uint32_t kFeatureVersion = 18; + + // Loading the license should start the playback clock. + LoadLicense(); + // Sleep until just after rental window is over. + wvutil::TestSleep::Sleep(kDuration + kShortSleep); + if (license_api_version_ < kFeatureVersion || + global_features.api_version < kFeatureVersion) { + // If the feature is not supported, then we expect failure because the + // playback clock was not started and we are outside the rental window. + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED)); + return; + } else { + // If the feature is supported, we expect decrypt to work because we are + // still within the initial renewal window, and the playback clock should + // have started. + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); + } + // This is after the initial renewal duration, so we expect failure before + // loading the renewal. + wvutil::TestSleep::Sleep(kShortSleep + kLongSleep); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); + + RenewalRoundTrip renewal_messages(&license_messages_); + MakeRenewalRequest(&renewal_messages); + LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); + + // After we've loaded the renewal, decrypt should succeed again. + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false)); +} + +TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadOutsideRentalDuration) { + license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load; + timer_limits_.rental_duration_seconds = kDuration; // 2 seconds. + timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds. + + // Sleep until just after rental window is over. + wvutil::TestSleep::Sleep(kDuration + kShortSleep); + // Loading the license should start the playback clock. + LoadLicense(); + // If the license is loaded after the rental duration window, we expect + // failure. + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + return; +} + INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest, Range(kCurrentAPI - 1, kCurrentAPI + 1)); @@ -4425,1182 +1603,10 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest, INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16, Range(kCoreMessagesAPI, kCurrentAPI + 1)); -// If the license does not allow a hash, then we should not compute one. -TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { - uint32_t hash_type = OEMCrypto_SupportsDecryptHash(); - // If hash is not supported, or is vendor defined, don't try to test it. - if (hash_type != OEMCrypto_CRC_Clear_Buffer) return; +/// @} - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - - uint32_t frame_number = 1; - uint32_t hash = 42; - // It is OK to set the hash before loading the keys - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_SetDecryptHash(session_.session_id(), frame_number, - reinterpret_cast(&hash), - sizeof(hash))); - // It is OK to select the key and decrypt. - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); - // But the error code should be bad. - ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, - OEMCrypto_GetHashErrorCode(session_.session_id(), &frame_number)); -} - -// 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](size_t hash_length) { - uint32_t frame_number = 1; - vector hash_buffer(hash_length); - return OEMCrypto_SetDecryptHash(session_id, frame_number, - hash_buffer.data(), hash_buffer.size()); - }; - TestHugeLengthDoesNotCrashAPI(f, kCheckStatus); -} - -// This test verifies OEMCrypto_SetDecryptHash for out of range frame number. -TEST_P(OEMCryptoLicenseTest, DecryptHashForOutOfRangeFrameNumber) { - uint32_t frame_number = kHugeRandomNumber; - uint32_t hash = 42; - ASSERT_NO_FATAL_FAILURE(OEMCrypto_SetDecryptHash( - session_.session_id(), frame_number, - reinterpret_cast(&hash), sizeof(hash))); -} - -// -// Decrypt Tests -- these test Decrypt CTR mode only. -// -TEST_P(OEMCryptoLicenseTest, Decrypt) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.core_response() - .timer_limits.total_playback_duration_seconds = kDuration; - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); -} - -// Verify that a zero duration means infinite license duration. -TEST_P(OEMCryptoLicenseTest, DecryptZeroDuration) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.core_response() - .timer_limits.total_playback_duration_seconds = 0; - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR()); -} - -struct SubsampleSize { - size_t clear_size; - size_t encrypted_size; - SubsampleSize(size_t clear, size_t encrypted) - : clear_size(clear), encrypted_size(encrypted) {} -}; - -// Struct for holding the data for one test sample in the decrypt tests. -struct TestSample { - // Encrypted data -- this is input to OEMCrypto, and output from EncryptData. - std::vector encrypted_buffer; - std::vector clear_buffer; // OEMCrypto store clear output here. - std::vector truth_buffer; // Truth data for clear text. - OEMCrypto_SampleDescription description; - std::vector subsamples; - int secure_buffer_fid; -}; - -// A class of tests that test decryption for a variety of patterns and modes. -// This test is parameterized by three parameters: -// 1. The pattern used for pattern decryption. -// 2. The cipher mode for decryption: either CTR or CBC. -// 3. A boolean that determines if decrypt in place should be done. When the -// output buffer is clear, it should be possible for the input and output -// buffers to be the same. -class OEMCryptoSessionTestsDecryptTests - : public OEMCryptoLicenseTestAPI16, - public WithParamInterface> { - protected: - void SetUp() override { - OEMCryptoLicenseTestAPI16::SetUp(); - pattern_ = ::testing::get<0>(GetParam()); - cipher_mode_ = ::testing::get<1>(GetParam()); - decrypt_inplace_ = ::testing::get<2>(GetParam()).decrypt_inplace; - output_buffer_type_ = ::testing::get<2>(GetParam()).type; - verify_crc_ = global_features.supports_crc; - // Pick a random key. - EXPECT_EQ(GetRandBytes(key_, sizeof(key_)), 1); - // Pick a random starting iv. Some tests override this before using it. - EXPECT_EQ(GetRandBytes(initial_iv_, sizeof(initial_iv_)), 1); - } - - void TearDown() override { - FreeSecureBuffers(); - OEMCryptoLicenseTestAPI16::TearDown(); - } - - void SetSubsampleSizes(std::vector subsample_sizes) { - // This is just sugar for having one sample with the given subsamples in it. - SetSampleSizes({subsample_sizes}); - } - - void SetSampleSizes(std::vector> sample_sizes) { - ASSERT_GT(sample_sizes.size(), 0u); - samples_.clear(); - samples_.reserve(sample_sizes.size()); - - // Convert all the size arrays to TestSample structs - for (const std::vector& subsample_sizes : sample_sizes) { - // This could be one line if we had C++17 - samples_.emplace_back(); - TestSample& sample = samples_.back(); - - ASSERT_GT(subsample_sizes.size(), 0u); - sample.subsamples.reserve(subsample_sizes.size()); - - // Convert all the sizes to subsample descriptions and tally the total - // sample size - size_t sample_size = 0; - size_t current_block_offset = 0; - for (const SubsampleSize& size : subsample_sizes) { - sample.subsamples.push_back(OEMCrypto_SubSampleDescription{ - size.clear_size, size.encrypted_size, - 0, // Subsample Flags, to be filled in after the loop - current_block_offset}); - - // Update the rolling variables - sample_size += size.clear_size + size.encrypted_size; - if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { - current_block_offset = - (current_block_offset + size.encrypted_size) % AES_BLOCK_SIZE; - } - } - - // Set the subsample flags now that all the subsamples are processed - sample.subsamples.front().subsample_flags |= OEMCrypto_FirstSubsample; - sample.subsamples.back().subsample_flags |= OEMCrypto_LastSubsample; - - // Set related information on the sample description - sample.description.subsamples = sample.subsamples.data(); - sample.description.subsamples_length = sample.subsamples.size(); - sample.description.buffers.input_data_length = sample_size; - } - } - - // Set up the input buffer and either a clear or secure output buffer for each - // test sample. This should be called after SetSubsampleSizes(). - void MakeBuffers() { - for (TestSample& sample : samples_) { - const size_t total_size = sample.description.buffers.input_data_length; - ASSERT_GT(total_size, 0u); - sample.encrypted_buffer.clear(); - sample.truth_buffer.clear(); - sample.clear_buffer.clear(); - sample.encrypted_buffer.resize(total_size); - sample.truth_buffer.resize(total_size); - for (size_t i = 0; i < total_size; i++) sample.truth_buffer[i] = i % 256; - - OEMCrypto_DestBufferDesc& output_descriptor = - sample.description.buffers.output_descriptor; - output_descriptor.type = output_buffer_type_; - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: - if (decrypt_inplace_) { - // Add some padding to verify there is no overrun. - sample.encrypted_buffer.resize(total_size + kBufferOverrunPadding, - 0xaa); - output_descriptor.buffer.clear.clear_buffer = - sample.encrypted_buffer.data(); - } else { - // Add some padding to verify there is no overrun. - sample.clear_buffer.resize(total_size + kBufferOverrunPadding, - 0xaa); - output_descriptor.buffer.clear.clear_buffer = - sample.clear_buffer.data(); - } - output_descriptor.buffer.clear.clear_buffer_length = total_size; - break; - - case OEMCrypto_BufferType_Secure: - output_descriptor.buffer.secure.secure_buffer_length = total_size; - ASSERT_EQ(OEMCrypto_AllocateSecureBuffer( - session_.session_id(), total_size, &output_descriptor, - &sample.secure_buffer_fid), - OEMCrypto_SUCCESS); - ASSERT_NE(output_descriptor.buffer.secure.secure_buffer, nullptr); - // It is OK if OEMCrypto changes the maximum size, but there must - // still be enough room for our data. - ASSERT_GE(output_descriptor.buffer.secure.secure_buffer_length, - total_size); - output_descriptor.buffer.secure.offset = 0; - break; - - case OEMCrypto_BufferType_Direct: - output_descriptor.buffer.direct.is_video = false; - break; - } // switch (output_descriptor.type) - } // sample loop - } - - void FreeSecureBuffers() { - for (TestSample& sample : samples_) { - OEMCrypto_DestBufferDesc& output_descriptor = - sample.description.buffers.output_descriptor; - if (output_descriptor.type == OEMCrypto_BufferType_Secure) { - ASSERT_EQ(OEMCrypto_FreeSecureBuffer(session_.session_id(), - &output_descriptor, - sample.secure_buffer_fid), - OEMCrypto_SUCCESS); - } - } - } - - void EncryptData() { - AES_KEY aes_key; - AES_set_encrypt_key(key_, AES_BLOCK_SIZE * 8, &aes_key); - - for (TestSample& sample : samples_) { - uint8_t iv[KEY_IV_SIZE]; // Current IV - memcpy(iv, initial_iv_, KEY_IV_SIZE); - memcpy(sample.description.iv, initial_iv_, KEY_IV_SIZE); - - size_t buffer_index = 0; // byte index into in and out. - size_t block_offset = 0; // byte index into current block. - for (const OEMCrypto_SubSampleDescription& subsample : - sample.subsamples) { - // Copy clear content. - if (subsample.num_bytes_clear > 0) { - memcpy(&sample.encrypted_buffer[buffer_index], - &sample.truth_buffer[buffer_index], subsample.num_bytes_clear); - buffer_index += subsample.num_bytes_clear; - } - - // The IV resets at the start of each subsample in the 'cbcs' schema. - if (cipher_mode_ == OEMCrypto_CipherMode_CBCS) { - memcpy(iv, initial_iv_, KEY_IV_SIZE); - } - - size_t pattern_offset = 0; - const size_t subsample_end = - buffer_index + subsample.num_bytes_encrypted; - while (buffer_index < subsample_end) { - const size_t size = - min(subsample_end - buffer_index, AES_BLOCK_SIZE - block_offset); - const size_t pattern_length = pattern_.encrypt + pattern_.skip; - const bool skip_block = - (pattern_offset >= pattern_.encrypt) && (pattern_length > 0); - if (pattern_length > 0) { - pattern_offset = (pattern_offset + 1) % pattern_length; - } - // CBC mode should just copy a partial block at the end. If there - // is a partial block at the beginning, an error is returned, so we - // can put whatever we want in the output buffer. - if (skip_block || ((cipher_mode_ == OEMCrypto_CipherMode_CBCS) && - (size < AES_BLOCK_SIZE))) { - memcpy(&sample.encrypted_buffer[buffer_index], - &sample.truth_buffer[buffer_index], size); - block_offset = 0; // Next block should be complete. - } else { - if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { - uint8_t aes_output[AES_BLOCK_SIZE]; - AES_encrypt(iv, aes_output, &aes_key); - for (size_t n = 0; n < size; n++) { - sample.encrypted_buffer[buffer_index + n] = - aes_output[n + block_offset] ^ - sample.truth_buffer[buffer_index + n]; - } - if (size + block_offset < AES_BLOCK_SIZE) { - // Partial block. Don't increment iv. Compute next block - // offset. - block_offset = block_offset + size; - } else { - EXPECT_EQ(block_offset + size, - static_cast(AES_BLOCK_SIZE)); - // Full block. Increment iv, and set offset to 0 for next - // block. - ctr128_inc64(1, iv); - block_offset = 0; - } - } else { - uint8_t aes_input[AES_BLOCK_SIZE]; - for (size_t n = 0; n < size; n++) { - aes_input[n] = sample.truth_buffer[buffer_index + n] ^ iv[n]; - } - AES_encrypt(aes_input, &sample.encrypted_buffer[buffer_index], - &aes_key); - memcpy(iv, &sample.encrypted_buffer[buffer_index], - AES_BLOCK_SIZE); - // CBC mode should always start on block boundary. - block_offset = 0; - } - } - buffer_index += size; - } // encryption loop - } // per-subsample loop - } // per-sample loop - } - - void LoadLicense() { - uint32_t control = wvoec::kControlNonceEnabled; - if (verify_crc_) control |= kControlAllowHashVerification; - if (output_buffer_type_ == OEMCrypto_BufferType_Secure) - control |= kControlObserveDataPath | kControlDataPathSecure; - license_messages_.set_control(control); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_response() - .timer_limits.initial_renewal_duration_seconds = kDuration; - memcpy(license_messages_.response_data().keys[0].key_data, key_, - sizeof(key_)); - license_messages_.response_data().keys[0].cipher_mode = cipher_mode_; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - ASSERT_EQ(OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, cipher_mode_), - OEMCrypto_SUCCESS); - } - - void TestDecryptCENC() { ASSERT_EQ(DecryptCENC(), OEMCrypto_SUCCESS); } - - void ValidateDecryptedData() { - for (TestSample& sample : samples_) { - if (sample.description.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - const size_t total_size = sample.description.buffers.input_data_length; - // To verify there is no buffer overrun after decrypting, look at the - // padded bytes just after the data buffer that was written. It - // should not have changed from the original 0xaa that we set in - // MakeBuffer function. - if (decrypt_inplace_) { - EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size, - sample.encrypted_buffer.end(), 0xaa), - static_cast(kBufferOverrunPadding)) - << "Buffer overrun."; - sample.encrypted_buffer.resize(total_size); // Remove padding. - // We expect encrypted buffer to have been changed by OEMCrypto. - EXPECT_EQ(sample.encrypted_buffer, sample.truth_buffer); - } else { - EXPECT_EQ(std::count(sample.clear_buffer.begin() + total_size, - sample.clear_buffer.end(), 0xaa), - static_cast(kBufferOverrunPadding)) - << "Buffer overrun."; - sample.clear_buffer.resize(total_size); // Remove padding. - EXPECT_EQ(sample.clear_buffer, sample.truth_buffer); - } - } - } - if (verify_crc_) { - uint32_t frame; - ASSERT_EQ(OEMCrypto_GetHashErrorCode(session_.session_id(), &frame), - OEMCrypto_SUCCESS); - } - } - - OEMCryptoResult DecryptCENC() { - // OEMCrypto only supports providing a decrypt hash for one sample. - if (samples_.size() > 1) verify_crc_ = false; - - // If supported, check the decrypt hashes. - if (verify_crc_) { - const TestSample& sample = samples_[0]; - - uint32_t hash = - util::wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size()); - OEMCrypto_SetDecryptHash(session_.session_id(), 1, - reinterpret_cast(&hash), - sizeof(hash)); - } - - // Build an array of just the sample descriptions. - std::vector sample_descriptions; - sample_descriptions.reserve(samples_.size()); - for (TestSample& sample : samples_) { - // This must be deferred until this point in case the test modifies the - // buffer before testing decrypt. - sample.description.buffers.input_data = sample.encrypted_buffer.data(); - // Append to the description array. - sample_descriptions.push_back(sample.description); - } - - // Perform decryption using the test data that was previously set up. - OEMCryptoResult result = DecryptFallbackChain::Decrypt( - session_.session_id(), sample_descriptions.data(), - sample_descriptions.size(), cipher_mode_, &pattern_); - if (result != OEMCrypto_SUCCESS) return result; - ValidateDecryptedData(); - return result; - } - - // Parameters of test case - OEMCrypto_CENCEncryptPatternDesc pattern_; - OEMCryptoCipherMode cipher_mode_; - bool decrypt_inplace_; // If true, input and output buffers are the same. - OEMCryptoBufferType output_buffer_type_; - - bool verify_crc_; - uint8_t key_[AES_BLOCK_SIZE]; // Encryption Key. - uint8_t initial_iv_[KEY_IV_SIZE]; // Starting IV for every sample. - std::vector samples_; -}; - -TEST_P(OEMCryptoSessionTestsDecryptTests, SingleLargeSubsample) { - // This subsample size is larger than a few encrypt/skip patterns. Most - // test cases use a pattern length of 160, so we'll run through at least two - // full patterns if we have more than 320 -- round up to 400. - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 400}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// When the pattern length is 10 blocks, there is a discrepancy between the -// HLS and the CENC standards for samples of size 160*N+16, for N = 1, 2, 3... -// We require the CENC standard for OEMCrypto, and let a layer above us break -// samples into pieces if they wish to use the HLS standard. -TEST_P(OEMCryptoSessionTestsDecryptTests, PatternPlusOneBlock) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 160 + 16}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// Test that a single block can be decrypted. -TEST_P(OEMCryptoSessionTestsDecryptTests, OneBlock) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 16}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests the ability to decrypt multiple subsamples with no offset. -// There is no offset within the block, used by CTR mode. -TEST_P(OEMCryptoSessionTestsDecryptTests, NoOffset) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {25, 160}, - {50, 256}, - {25, 160}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests an offset into the block for the second encrypted subsample. -// This should only work for CTR mode, for CBC mode an error is expected in -// the decrypt step. -// If this test fails for CTR mode, then it is probably handling the -// block_offset incorrectly. -TEST_P(OEMCryptoSessionTestsDecryptTests, EvenOffset) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {25, 8}, - {25, 32}, - {25, 50}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - // CTR Mode is self-inverse -- i.e. We can pick the encrypted data and - // compute the unencrypted data. By picking the encrypted data to be all 0, - // it is easier to re-encrypt the data and debug problems. Similarly, we - // pick an iv = 0. - memset(initial_iv_, 0, KEY_IV_SIZE); - TestSample& sample = samples_[0]; // There is only one sample in this test - sample.truth_buffer.assign(sample.description.buffers.input_data_length, 0); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - if (decrypt_inplace_) { - const size_t total_size = sample.description.buffers.input_data_length; - // In case of decrypt_inplace_, encrypted_buffer contains padded bytes - // which is used for buffer overrun validation. Do not copy the padded - // bytes to truth_buffer. - sample.truth_buffer.assign(sample.encrypted_buffer.begin(), - sample.encrypted_buffer.begin() + total_size); - } else { - sample.truth_buffer = - sample.encrypted_buffer; // truth_buffer_ = encrypted zero buffer. - } - // Run EncryptData to re-encrypt this buffer. For CTR mode, we should get - // back to zeros. - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// If the EvenOffset test passes, but this one doesn't, then DecryptCENC might -// be using the wrong definition of block offset. Adding the block offset to -// the block boundary should give you the beginning of the encrypted data. -// This should only work for CTR mode, for CBC mode, the block offset must be -// 0, so an error is expected in the decrypt step. -// Another way to view the block offset is with the formula: -// block_boundary + block_offset = beginning of subsample. -TEST_P(OEMCryptoSessionTestsDecryptTests, OddOffset) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {10, 50}, - {10, 75}, - {10, 75}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests that the algorithm used to increment the counter for -// AES-CTR mode is correct. There are two possible implementations: -// 1) increment the counter as if it were a 128 bit number, -// 2) increment the low 64 bits as a 64 bit number and leave the high bits -// alone. -// For CENC, the algorithm we should use is the second one. OpenSSL defaults to -// the first. If this test is not passing, you should look at the way you -// increment the counter. Look at the example code in ctr128_inc64 above. -// If you start with an IV of 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, after you -// increment twice, you should get 0xFFFFFFFFFFFFFFFF0000000000000000. -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptWithNearWrap) { - memcpy(initial_iv_, - wvutil::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), - KEY_IV_SIZE); - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 256}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests the case where an encrypted sample is not an even number of -// blocks. For CTR mode, the partial block is encrypted. For CBC mode the -// partial block should be a copy of the clear data. -TEST_P(OEMCryptoSessionTestsDecryptTests, PartialBlock) { - // Note: for more complete test coverage, we want a sample size that is in - // the encrypted range for some tests, e.g. (3,7), and in the skip range for - // other tests, e.g. (7, 3). 3*16 < 50 and 7*16 > 50. - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 50}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// Based on the resource rating, OEMCrypto should be able to handle the maximum -// amount of data that can be passed to it. This is the lesser of: -// -// 1) The maximum total sample size -// 2) The maximum number of subsamples multiplied by the maximum subsample size -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) { - const size_t max_sample_size = GetResourceValue(kMaxSampleSize); - const size_t max_subsample_size = GetResourceValue(kMaxSubsampleSize); - const size_t max_num_subsamples = GetResourceValue(kMaxNumberSubsamples); - - // The +1 on this line ensures that, even in cases where max_sample_size is - // not evenly divisible by max_num_subsamples and thus the division gets - // truncated, (max_num_subsamples * subsample_size) will be greater than - // max_sample_size. - const size_t subsample_size = - std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size); - size_t bytes_remaining = max_sample_size; - std::vector subsample_sizes; - while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) { - const size_t this_subsample_size = - std::min(subsample_size, bytes_remaining); - const size_t clear_size = this_subsample_size / 2; - const size_t encrypted_size = this_subsample_size - clear_size; - - subsample_sizes.push_back({clear_size, encrypted_size}); - bytes_remaining -= this_subsample_size; - } - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes(subsample_sizes)); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -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); - LoadLicense(); - MakeBuffers(); - EncryptData(); - OEMCryptoResult result = DecryptCENC(); - // Closing the session and opening it for next iteration. - // If it is last iteration, session will be closed in teardown method of - // class. - session_.close(); - session_.open(); - InstallTestRSAKey(&session_); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); -} - -TEST_P(OEMCryptoSessionTestsDecryptTests, - OEMCryptoMemoryCheckDecryptCENCStatusForHugeNumberOfSubSamples) { - size_t number_of_subsamples = 10000; - std::vector subsample_sizes; - while (number_of_subsamples-- > 0) { - subsample_sizes.push_back({100, 100}); - } - SetSubsampleSizes(subsample_sizes); - LoadLicense(); - MakeBuffers(); - EncryptData(); - // Build an array of just the sample descriptions. - std::vector sample_descriptions; - sample_descriptions.reserve(samples_.size()); - for (TestSample& sample : samples_) { - // This must be deferred until this point in case the test modifies the - // buffer before testing decrypt. - sample.description.buffers.input_data = sample.encrypted_buffer.data(); - // Append to the description array. - sample_descriptions.push_back(sample.description); - } - OEMCryptoResult result = OEMCrypto_DecryptCENC( - session_.session_id(), sample_descriptions.data(), 1, &pattern_); - LOGD("Large number of subsamples test has return code %d", result); -} - -TEST_P(OEMCryptoSessionTestsDecryptTests, - OEMCryptoMemoryCheckDecryptCENCStatusForHugeSubSample) { - std::vector subsample_sizes; - subsample_sizes.push_back({100000, 100000}); - SetSubsampleSizes(subsample_sizes); - LoadLicense(); - MakeBuffers(); - EncryptData(); - // Build an array of just the sample descriptions. - std::vector sample_descriptions; - sample_descriptions.reserve(samples_.size()); - for (TestSample& sample : samples_) { - // This must be deferred until this point in case the test modifies the - // buffer before testing decrypt. - sample.description.buffers.input_data = sample.encrypted_buffer.data(); - // Append to the description array. - sample_descriptions.push_back(sample.description); - } - OEMCryptoResult result = OEMCrypto_DecryptCENC( - session_.session_id(), sample_descriptions.data(), 1, &pattern_); - LOGD("Large subsample test has return code %d", result); -} - -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); - LoadLicense(); - MakeBuffers(); - EncryptData(); - OEMCryptoResult result = DecryptCENC(); - // Closing the session and opening it for next iteration. - // If it is last iteration, session will be closed in teardown method of - // class. - session_.close(); - session_.open(); - InstallTestRSAKey(&session_); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); -} - -// Based on the resource rating, OEMCrypto should be able to handle the maximum -// subsample size. -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) { - const size_t max = GetResourceValue(kMaxSubsampleSize); - const size_t half_max = max / 2; - // This test assumes that the maximum sample size is always more than three - // times the maximum subsample size. - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {max, 0}, - {0, max}, - {half_max, max - half_max}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// There are probably no frames this small, but we should handle them anyway. -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptSmallBuffer) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {5, 5}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// Test the case where there is only a clear subsample and no encrypted -// subsample. -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptUnencrypted) { - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {256, 0}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptUnencryptedNoKey) { - // Do not try to compute the CRC because we have not loaded a license. - verify_crc_ = false; - // Single clear subsample - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {400, 0}, - })); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - // Clear data should be copied even if there is no key selected, and no - // license loaded. - // ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests the ability to decrypt multiple samples at once. -TEST_P(OEMCryptoSessionTestsDecryptTests, MultipleSamples) { - ASSERT_NO_FATAL_FAILURE(SetSampleSizes({ - { - {52, 160}, - {25, 256}, - {25, 320}, - }, - { - {300, 64}, - {50, 160}, - {2, 160}, - {24, 160}, - {128, 256}, - }, - { - {70, 320}, - {160, 160}, - }, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// This tests that calling OEMCrypto_Idle and OEMCrypto_Wake once or multiple -// times doesn't break anything. -TEST_P(OEMCryptoSessionTestsDecryptTests, IdleAndWake) { - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); -} - -// This tests that after an idle and a wake, decryption can continue in an -// open session. -TEST_P(OEMCryptoSessionTestsDecryptTests, ContinueDecryptionAfterIdleAndWake) { - // This subsample size is larger than a few encrypt/skip patterns. Most - // test cases use a pattern length of 160, so we'll run through at least two - // full patterns if we have more than 320 -- round up to 400. - ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ - {0, 400}, - })); - ASSERT_NO_FATAL_FAILURE(LoadLicense()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); - // Set state to idle then wake again and try to reencrypt/decrypt - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); - ASSERT_NO_FATAL_FAILURE(MakeBuffers()); - ASSERT_NO_FATAL_FAILURE(EncryptData()); - ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); -} - -// Used to construct a specific pattern. -constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, - size_t skip) { - return {encrypt, skip}; -} - -INSTANTIATE_TEST_SUITE_P( - CTRTests, OEMCryptoSessionTestsDecryptTests, - Combine(Values(MakePattern(0, 0)), Values(OEMCrypto_CipherMode_CENC), - ::testing::ValuesIn(global_features.GetOutputTypes()))); - -// Decrypt in place for CBC tests was only required in v13. -INSTANTIATE_TEST_SUITE_P( - CBCTestsAPI14, OEMCryptoSessionTestsDecryptTests, - Combine( - Values(MakePattern(3, 7), MakePattern(9, 1), - // HLS edge cases. We should follow the CENC spec, not HLS spec. - MakePattern(1, 9), MakePattern(1, 0), - // AV1 patterns not already covered above. - MakePattern(5, 5), MakePattern(10, 0)), - Values(OEMCrypto_CipherMode_CBCS), - ::testing::ValuesIn(global_features.GetOutputTypes()))); - -// A request to decrypt data to a clear buffer when the key control block -// requires a secure data path. -TEST_P(OEMCryptoLicenseTest, DecryptSecureToClear) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.set_control(wvoec::kControlObserveDataPath | - wvoec::kControlDataPathSecure); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - ASSERT_NO_FATAL_FAILURE( - session_.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// Test that key duration is honored. -TEST_P(OEMCryptoLicenseTest, KeyDuration) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - license_messages_.core_response() - .timer_limits.total_playback_duration_seconds = kDuration; - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); - wvutil::TestSleep::Sleep(kShortSleep); // Should still be valid key. - ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false, OEMCrypto_SUCCESS)); - wvutil::TestSleep::Sleep(kLongSleep); // Should be expired key. - ASSERT_NO_FATAL_FAILURE( - session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); - ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(0)); -} - -INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, - Range(kCoreMessagesAPI, kCurrentAPI + 1)); - -// -// Certificate Root of Trust Tests -// -class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest { - protected: - void TestPrepareProvisioningRequestForHugeBufferLengths( - const std::function f, - bool check_status) { - auto oemcrypto_function = [&](size_t message_length) { - Session s; - s.open(); - if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { - s.LoadOEMCert(true); - } else { - s.GenerateDerivedKeysFromKeybox(keybox_); - } - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - f(message_length, &provisioning_messages); - return provisioning_messages - .SignAndCreateRequestWithCustomBufferLengths(); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - void TestLoadProvisioningForHugeBufferLengths( - const std::function f, - bool check_status, bool update_core_message_substring_values) { - auto oemcrypto_function = [&](size_t message_length) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - provisioning_messages.SignAndVerifyRequest(); - provisioning_messages.CreateDefaultResponse(); - if (update_core_message_substring_values) { - // Make provisioning message big enough so that updated core message - // substring offset and length values from tests are still able to read - // valid data from provisioning_message buffer rather than some garbage - // data. - provisioning_messages.set_message_size( - sizeof(provisioning_messages.response_data()) + message_length); - } - f(message_length, &provisioning_messages); - provisioning_messages - .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); - OEMCryptoResult result = provisioning_messages.LoadResponse(); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - void TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - const std::function f) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - provisioning_messages.SignAndVerifyRequest(); - provisioning_messages.CreateDefaultResponse(); - size_t message_length = sizeof(provisioning_messages.response_data()); - f(message_length, &provisioning_messages); - provisioning_messages - .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); - OEMCryptoResult result = provisioning_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); - } -}; - -// This test verifies that we can create a wrapped RSA key, and then reload it. -TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); -} - -TEST_F(OEMCryptoLoadsCertificate, SignProvisioningRequest) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { - s.LoadOEMCert(true); - } else { - EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox); - s.GenerateDerivedKeysFromKeybox(keybox_); - } - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); -} - -// This tests a large message size. The size is larger than we required in v15. -TEST_F(OEMCryptoLoadsCertificate, SignLargeProvisioningRequestAPI16) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { - s.LoadOEMCert(true); - } else { - EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox); - s.GenerateDerivedKeysFromKeybox(keybox_); - } - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - const size_t max_size = GetResourceValue(kLargeMessageSize); - provisioning_messages.set_message_size(max_size); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); -} - -// This creates a wrapped RSA key, and then does the sanity check that the -// unencrypted key is not found in the wrapped key. The wrapped key should be -// encrypted. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - // We should not be able to find the rsa key in the wrapped key. It should - // be encrypted. - EXPECT_EQ(nullptr, find(provisioning_messages.wrapped_rsa_key(), - provisioning_messages.encoded_rsa_key())); -} - -// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning -// message. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - // Encrypt and sign once, so that we can use the size of the response. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - provisioning_messages.core_response().enc_private_key.offset = - provisioning_messages.encrypted_response_buffer().size() + 1; - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning -// message. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - // Encrypt and sign once, so that we can use the size of the response. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - provisioning_messages.core_response().enc_private_key_iv.offset = - provisioning_messages.encrypted_response_buffer().size() + 1; - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning -// message. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - // Encrypt and sign once, so that we can use the size of the response. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - // If the offset is before the end, but the offset+length is bigger, then - // the message should be rejected. - provisioning_messages.core_response().enc_private_key.offset = - provisioning_messages.encrypted_response_buffer().size() - 5; - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning -// message. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange4_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - // Encrypt and sign once, so that we can use the size of the response. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - // If the offset is before the end, but the offset+length is bigger, then - // the message should be rejected. - provisioning_messages.core_response().enc_private_key_iv.offset = - provisioning_messages.encrypted_response_buffer().size() - 5; - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Verify that RewrapDeviceRSAKey checks pointers are within the provisioning -// message. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange5Prov30_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - // Encrypt and sign once, so that we can use the size of the response. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - // If the offset is before the end, but the offset+length is bigger, then - // the message should be rejected. - provisioning_messages.core_response().encrypted_message_key.offset = - provisioning_messages.encrypted_response_buffer().size() + 1; - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Test that RewrapDeviceRSAKey verifies the message signature. -// TODO(b/144186970): This test should also run on Prov 3.0 devices. -TEST_F(OEMCryptoLoadsCertificate, - CertificateProvisionBadSignatureKeyboxTestAPI16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - provisioning_messages.response_signature()[4] ^= 42; // bad signature. - ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, - provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Test that RewrapDeviceRSAKey verifies the nonce is current. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce_API16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - provisioning_messages.core_request().nonce ^= 42; // bad nonce. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, - provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Test that RewrapDeviceRSAKey verifies the RSA key is valid. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - provisioning_messages.response_data().rsa_key[4] ^= 42; // bad key. - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Test that RewrapDeviceRSAKey verifies the RSA key is valid. -// TODO(b/144186970): This test should also run on Prov 3.0 devices. -TEST_F(OEMCryptoLoadsCertificate, - CertificateProvisionBadRSAKeyKeyboxTestAPI16) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - size_t rsa_offset = - provisioning_messages.core_response().enc_private_key.offset; - // Offsets are relative to the message body, after the core message. - rsa_offset += provisioning_messages.serialized_core_message().size(); - rsa_offset += 4; // Change the middle of the key. - provisioning_messages.encrypted_response_buffer()[rsa_offset] ^= 42; - ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, - provisioning_messages.LoadResponse()); - provisioning_messages.VerifyLoadFailed(); -} - -// Test that RewrapDeviceRSAKey accepts the maximum message size. -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - const size_t max_size = GetResourceValue(kLargeMessageSize); - provisioning_messages.set_message_size(max_size); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse()); - // We should not be able to find the rsa key in the wrapped key. It should - // be encrypted. - EXPECT_EQ(nullptr, find(provisioning_messages.wrapped_rsa_key(), - provisioning_messages.encoded_rsa_key())); -} +/// @addtogroup security +/// @{ TEST_F(OEMCryptoLoadsCertificate, OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { @@ -5756,122 +1762,29 @@ TEST_F( }); } -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeSignatureLength) { - auto oemcrypto_function = [&](size_t signature_size) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - provisioning_messages.SignAndVerifyRequest(); - provisioning_messages.CreateDefaultResponse(); - provisioning_messages.EncryptAndSignResponse(); - vector signature(signature_size); - size_t wrapped_private_key_length = 0; - // Find wrapped_private_key_length. - OEMCrypto_LoadProvisioning( - s.session_id(), - 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); - OEMCryptoResult result = OEMCrypto_LoadProvisioning( - s.session_id(), - 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(), - &wrapped_private_key_length); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} +/// @} -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeWrappedRsaKeyLength) { - auto oemcrypto_function = [&](size_t buffer_length) { - Session s; - ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - provisioning_messages.SignAndVerifyRequest(); - provisioning_messages.CreateDefaultResponse(); - provisioning_messages.EncryptAndSignResponse(); - size_t wrapped_private_key_length = buffer_length; - vector wrapped_private_key(wrapped_private_key_length); - OEMCryptoResult result = OEMCrypto_LoadProvisioning( - s.session_id(), - provisioning_messages.encrypted_response_buffer().data(), - provisioning_messages.encrypted_response_buffer().size(), - provisioning_messages.serialized_core_message().size(), - provisioning_messages.response_signature().data(), - provisioning_messages.response_signature().size(), - wrapped_private_key.data(), &wrapped_private_key_length); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} +/// @addtogroup provision +/// @{ // Test that a wrapped RSA key can be loaded. TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); -} - -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLength) { - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { - Session s; - s.open(); - vector wrapped_rsa_key_buffer = wrapped_rsa_key_; - wrapped_rsa_key_buffer.resize(wrapped_rsa_key_length); - OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( - s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_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(), - kHugeInputBufferLength, !kCheckStatus); -} - -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLengthStartingFromLength1) { - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { - Session s; - s.open(); - vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); - OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( - s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_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, !kCheckStatus); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); } class OEMCryptoLoadsCertVariousKeys : public OEMCryptoLoadsCertificate { public: void TestKey(const uint8_t* key, size_t key_length) { encoded_rsa_key_.assign(key, key + key_length); - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); LicenseRoundTrip license_messages(&s); ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); @@ -5936,23 +1849,23 @@ TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerZeroNormalDer) { // This tests that two sessions can use different RSA keys simultaneously. TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) { - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); Session s1; // Session s1 loads the default rsa key, but doesn't use it // until after s2 uses its key. ASSERT_NO_FATAL_FAILURE(s1.open()); ASSERT_NO_FATAL_FAILURE(s1.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); - ASSERT_NO_FATAL_FAILURE(s1.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s1.LoadWrappedRsaDrmKey(wrapped_drm_key_)); Session s2; // Session s2 uses a different rsa key. encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048, kTestRSAPKCS8PrivateKeyInfo4_2048 + sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048)); - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(s2.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); - ASSERT_NO_FATAL_FAILURE(s2.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s2.LoadWrappedRsaDrmKey(wrapped_drm_key_)); LicenseRoundTrip license_messages2(&s2); ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages2.CreateDefaultResponse()); @@ -5984,30 +1897,48 @@ TEST_F(OEMCryptoLoadsCertificate, TestMaxDRMKeys) { const size_t key_index = i % kTestRSAPKCS8PrivateKeys_2048.size(); encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeys_2048[key_index].begin(), kTestRSAPKCS8PrivateKeys_2048[key_index].end()); - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); - ASSERT_NO_FATAL_FAILURE(sessions[i]->SetRsaPublicKeyFromPrivateKeyInfo( - encoded_rsa_key_.data(), encoded_rsa_key_.size())); - ASSERT_NO_FATAL_FAILURE( - sessions[i]->LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(sessions[i].get())); } // Attempts to load one more key than the kMaxTotalDRMPrivateKeys - Session s; - encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo2_2048, - kTestRSAPKCS8PrivateKeyInfo2_2048 + - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); - Session ps; - ProvisioningRoundTrip provisioning_messages(&ps, encoded_rsa_key_); - provisioning_messages.PrepareSession(keybox_); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); - OEMCryptoResult result = provisioning_messages.LoadResponse(); - // Key loading is allowed to fail due to resource restriction - if (result != OEMCrypto_SUCCESS) { - ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES || - result == OEMCrypto_ERROR_TOO_MANY_KEYS); + if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + Session s; + const size_t buffer_size = 5000; // Make sure it is large enough. + std::vector public_key(buffer_size); + size_t public_key_size = buffer_size; + std::vector public_key_signature(buffer_size); + size_t public_key_signature_size = buffer_size; + std::vector wrapped_private_key(buffer_size); + size_t wrapped_private_key_size = buffer_size; + OEMCrypto_PrivateKeyType key_type; + OEMCryptoResult result = OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type); + // Key creation is allowed to fail due to resource restriction + if (result != OEMCrypto_SUCCESS) { + ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES || + result == OEMCrypto_ERROR_TOO_MANY_KEYS); + } + } else { + Session s; + encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo2_2048, + kTestRSAPKCS8PrivateKeyInfo2_2048 + + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); + Session ps; + ProvisioningRoundTrip provisioning_messages(&ps, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + // Key loading is allowed to fail due to resource restriction + if (result != OEMCrypto_SUCCESS) { + ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES || + result == OEMCrypto_ERROR_TOO_MANY_KEYS); + } } // Verifies that the DRM keys which are already loaded should still function for (size_t i = 0; i < licenses.size(); i++) { @@ -6026,6 +1957,11 @@ TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) { << "Supported certificates is only " << OEMCrypto_SupportedCertificates(); } +/// @} + +/// @addtogroup security +/// @{ + TEST_F(OEMCryptoLoadsCertificate, OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { TestPrepareProvisioningRequestForHugeBufferLengths( @@ -6053,6 +1989,11 @@ TEST_F(OEMCryptoLoadsCertificate, kCheckStatus); } +/// @} + +/// @addtogroup provision +/// @{ + // These tests are run by all L1 devices that load and use certificates. It is // also run by a few L3 devices that use a baked in certificate, but cannot load // a certificate. @@ -6066,7 +2007,7 @@ class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate { ASSERT_NO_FATAL_FAILURE(session_.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); } else { - InstallTestRSAKey(&session_); + InstallTestDrmKey(&session_); } } @@ -6089,20 +2030,20 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { auto start_time = clock.now(); int count = 15; for (int i = 0; i < count; i++) { // Only 20 nonce available. - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); } auto delta_time = clock.now() - start_time; const double provision_time = delta_time / std::chrono::milliseconds(1) / count; Session session; - ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); start_time = clock.now(); count = 0; while (clock.now() - start_time < kTestDuration) { 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_)); const size_t size = 50; vector licenseRequest(size); GetRandBytes(licenseRequest.data(), licenseRequest.size()); @@ -6140,7 +2081,7 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { 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 session_key; vector enc_session_key; ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo( @@ -6208,66 +2149,10 @@ TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) { enc_context.data(), enc_context.size())); } -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(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_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); -} +/// @addtogroup cast +/// @{ // This test attempts to use alternate algorithms for loaded device certs. class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { @@ -6276,7 +2161,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { OEMCryptoResult sts; 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_)); // Sign a Message vector licenseRequest(size); @@ -6305,7 +2190,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { void TestSignature(RSA_Padding_Scheme scheme, size_t size) { 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 licenseRequest(size); GetRandBytes(licenseRequest.data(), licenseRequest.size()); @@ -6334,7 +2219,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { void DisallowDeriveKeys() { 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_)); s.GenerateNonce(); vector session_key; vector enc_session_key; @@ -6363,10 +2248,13 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { OEMCryptoResult sts = provisioning_messages.LoadResponse(); key_loaded_ = (OEMCrypto_SUCCESS == sts); if (key_loaded_) { - encoded_rsa_key_ = provisioning_messages.encoded_rsa_key(); - wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key(); - EXPECT_GT(wrapped_rsa_key_.size(), 0u); - EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_)); + uint8_t* ptr = provisioning_messages.response_data().rsa_key; + size_t len = provisioning_messages.response_data().rsa_key_length; + encoded_rsa_key_ = std::vector(ptr, ptr + len); + wrapped_drm_key_ = provisioning_messages.wrapped_rsa_key(); + drm_key_type_ = OEMCrypto_RSA_Private_Key; + EXPECT_GT(wrapped_drm_key_.size(), 0u); + EXPECT_EQ(nullptr, find(wrapped_drm_key_, encoded_rsa_key_)); } if (force) { EXPECT_EQ(OEMCrypto_SUCCESS, sts); @@ -6376,64 +2264,6 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { bool key_loaded_ = false; }; -TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForHugeBuffer) { - OEMCryptoResult sts; - LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); - // If the device is a cast receiver, then this scheme is required. - if (global_features.cast_receiver) { - ASSERT_TRUE(key_loaded_); - } - if (key_loaded_) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); - - vector message_buffer(10); - size_t signature_length = 0; - sts = OEMCrypto_GenerateRSASignature(s.session_id(), message_buffer.data(), - message_buffer.size(), nullptr, - &signature_length, kSign_PKCS1_Block1); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_NE(static_cast(0), signature_length); - vector signature(signature_length); - - auto oemcrypto_function = [&](size_t buffer_length) { - message_buffer.resize(buffer_length); - return OEMCrypto_GenerateRSASignature( - s.session_id(), message_buffer.data(), message_buffer.size(), - signature.data(), &signature_length, kSign_PKCS1_Block1); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); - s.close(); - } -} - -TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForHugeSignatureLength) { - LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); - // If the device is a cast receiver, then this scheme is required. - if (global_features.cast_receiver) { - ASSERT_TRUE(key_loaded_); - } - if (key_loaded_) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); - - vector message_buffer(50); - vector signature; - auto oemcrypto_function = [&](size_t signature_length) { - signature.resize(signature_length); - return OEMCrypto_GenerateRSASignature( - s.session_id(), message_buffer.data(), message_buffer.size(), - signature.data(), &signature_length, kSign_PKCS1_Block1); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); - s.close(); - } -} - // The alternate padding is only required for cast receivers, but all devices // should forbid the alternate padding for regular certificates. TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) { @@ -6474,6 +2304,13 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { // those devices. class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { protected: + void SetUp() override { + OEMCryptoLoadsCertificateAlternates::SetUp(); + if (!global_features.cast_receiver) { + GTEST_SKIP() << "OEMCrypto does not support CAST Receiver functionality"; + } + } + vector encode(uint8_t type, const vector& substring) { vector result; result.push_back(type); @@ -6629,7 +2466,7 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { OEMCryptoResult sts; 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_)); // The application will compute the SHA-1 Hash of the message, so this // test must do that also. @@ -7377,266 +3214,10 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) { TestSignature(kSign_PKCS1_Block1, message, signature); } -// This class is for testing the generic crypto functionality. -class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { - protected: - // buffer_size_ must be a multiple of encryption block size, 16. We'll use a - // reasonable number of blocks for most of the tests. - OEMCryptoGenericCryptoTest() : buffer_size_(160) {} +/// @} - void SetUp() override { - OEMCryptoRefreshTest::SetUp(); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE( - license_messages_.CreateResponseWithGenericCryptoKeys()); - InitializeClearBuffer(); - } - - void InitializeClearBuffer() { - clear_buffer_.assign(buffer_size_, 0); - for (size_t i = 0; i < clear_buffer_.size(); i++) { - clear_buffer_[i] = 1 + i % 250; - } - for (size_t i = 0; i < wvoec::KEY_IV_SIZE; i++) { - iv_[i] = i; - } - } - - void ResizeBuffer(size_t new_size) { - buffer_size_ = new_size; - InitializeClearBuffer(); // Re-initialize the clear buffer. - } - - void EncryptAndLoadKeys() { - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - } - - // Encrypt the buffer with the specified key made in - // CreateResponseWithGenericCryptoKeys. - void EncryptBuffer(unsigned int key_index, const vector& in_buffer, - vector* out_buffer) { - EncryptBufferWithKey(session_.license().keys[key_index].key_data, in_buffer, - out_buffer); - } - // Encrypt the buffer with the specified key. - void EncryptBufferWithKey(const uint8_t* key_data, - const vector& in_buffer, - vector* out_buffer) { - AES_KEY aes_key; - ASSERT_EQ(0, AES_set_encrypt_key(key_data, AES_BLOCK_SIZE * 8, &aes_key)); - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, iv_, wvoec::KEY_IV_SIZE); - out_buffer->resize(in_buffer.size()); - ASSERT_GT(in_buffer.size(), 0u); - ASSERT_EQ(0u, in_buffer.size() % AES_BLOCK_SIZE); - AES_cbc_encrypt(in_buffer.data(), out_buffer->data(), in_buffer.size(), - &aes_key, iv_buffer, AES_ENCRYPT); - } - - // Sign the buffer with the specified key made in - // CreateResponseWithGenericCryptoKeys. - void SignBuffer(unsigned int key_index, const vector& in_buffer, - vector* signature) { - SignBufferWithKey(session_.license().keys[key_index].key_data, in_buffer, - signature); - } - - // Sign the buffer with the specified key. - void SignBufferWithKey(const uint8_t* key_data, - const vector& in_buffer, - vector* signature) { - unsigned int md_len = SHA256_DIGEST_LENGTH; - signature->resize(SHA256_DIGEST_LENGTH); - HMAC(EVP_sha256(), key_data, wvoec::MAC_KEY_SIZE, in_buffer.data(), - in_buffer.size(), signature->data(), &md_len); - } - - OEMCryptoResult GenericEncrypt(OEMCrypto_SESSION session, - const uint8_t* clear_buffer, - size_t clear_buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_generic_encrypt_fuzz_seed_corpus"); - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; - fuzzed_structure.algorithm = algorithm; - // Cipher mode and algorithm. - AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), - sizeof(fuzzed_structure)); - AppendToFile(file_name, reinterpret_cast(iv), - wvoec::KEY_IV_SIZE); - AppendSeparator(file_name); - AppendToFile(file_name, reinterpret_cast(clear_buffer), - clear_buffer_length); - } - return OEMCrypto_Generic_Encrypt(session, clear_buffer, clear_buffer_length, - iv, algorithm, out_buffer); - } - - OEMCryptoResult GenericDecrypt(OEMCrypto_SESSION session, - const uint8_t* encrypted_buffer, - size_t encrypted_buffer_length, - const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_generic_decrypt_fuzz_seed_corpus"); - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; - fuzzed_structure.algorithm = algorithm; - // Cipher mode and algorithm. - AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), - sizeof(fuzzed_structure)); - AppendToFile(file_name, reinterpret_cast(iv), - wvoec::KEY_IV_SIZE); - AppendSeparator(file_name); - AppendToFile(file_name, reinterpret_cast(encrypted_buffer), - encrypted_buffer_length); - } - return OEMCrypto_Generic_Decrypt(session, encrypted_buffer, - encrypted_buffer_length, iv, algorithm, - out_buffer); - } - - OEMCryptoResult GenericVerify(OEMCrypto_SESSION session, - const uint8_t* clear_buffer, - size_t clear_buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length) { - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; - fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; - fuzzed_structure.algorithm = algorithm; - fuzzed_structure.signature_length = signature_length; - // Cipher mode and algorithm. - AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), - sizeof(fuzzed_structure)); - AppendToFile(file_name, reinterpret_cast(clear_buffer), - clear_buffer_length); - } - return OEMCrypto_Generic_Verify(session, clear_buffer, clear_buffer_length, - algorithm, signature, signature_length); - } - - OEMCryptoResult GenericSign(OEMCrypto_SESSION session, - const uint8_t* clear_buffer, - size_t clear_buffer_length, - OEMCrypto_Algorithm algorithm, uint8_t* signature, - size_t* signature_length) { - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_generic_sign_fuzz_seed_corpus"); - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; - fuzzed_structure.algorithm = algorithm; - // Cipher mode and algorithm. - AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), - sizeof(fuzzed_structure)); - AppendToFile(file_name, reinterpret_cast(clear_buffer), - clear_buffer_length); - } - return OEMCrypto_Generic_Sign(session, clear_buffer, clear_buffer_length, - algorithm, signature, signature_length); - } - - // This asks OEMCrypto to encrypt with the specified key, and expects a - // failure. - void BadEncrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, - size_t buffer_length) { - OEMCryptoResult sts; - vector expected_encrypted; - EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); - sts = OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - vector encrypted(buffer_length); - sts = GenericEncrypt(session_.session_id(), clear_buffer_.data(), - buffer_length, iv_, algorithm, encrypted.data()); - EXPECT_NE(OEMCrypto_SUCCESS, sts); - expected_encrypted.resize(buffer_length); - EXPECT_NE(encrypted, expected_encrypted); - } - - // This asks OEMCrypto to decrypt with the specified key, and expects a - // failure. - void BadDecrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, - size_t buffer_length) { - OEMCryptoResult sts; - vector encrypted; - EncryptBuffer(key_index, clear_buffer_, &encrypted); - sts = OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - vector resultant(encrypted.size()); - sts = GenericDecrypt(session_.session_id(), encrypted.data(), buffer_length, - iv_, algorithm, resultant.data()); - EXPECT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(clear_buffer_, resultant); - } - - // This asks OEMCrypto to sign with the specified key, and expects a - // failure. - void BadSign(unsigned int key_index, OEMCrypto_Algorithm algorithm) { - OEMCryptoResult sts; - vector expected_signature; - SignBuffer(key_index, clear_buffer_, &expected_signature); - - sts = OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; - vector signature(SHA256_DIGEST_LENGTH); - sts = GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, signature.data(), - &signature_length); - EXPECT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(signature, expected_signature); - } - - // This asks OEMCrypto to verify a signature with the specified key, and - // expects a failure. - void BadVerify(unsigned int key_index, OEMCrypto_Algorithm algorithm, - size_t signature_size, bool alter_data) { - OEMCryptoResult sts; - vector signature; - SignBuffer(key_index, clear_buffer_, &signature); - if (alter_data) { - signature[0] ^= 42; - } - if (signature.size() < signature_size) { - signature.resize(signature_size); - } - - sts = OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = GenericVerify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, signature.data(), - signature_size); - EXPECT_NE(OEMCrypto_SUCCESS, sts); - } - - // This must be a multiple of encryption block size. - size_t buffer_size_; - vector clear_buffer_; - vector encrypted_buffer_; - uint8_t iv_[wvoec::KEY_IV_SIZE]; -}; +/// @addtogroup generic +/// @{ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); } @@ -7646,16 +3227,17 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) { unsigned int key_index = 0; vector expected_encrypted; EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector encrypted(clear_buffer_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, - GenericEncrypt(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), iv_, + GenericEncrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -7678,71 +3260,38 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) { unsigned int key_index = 0; vector expected_encrypted; EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); // Input and output are same buffer: vector buffer = clear_buffer_; - ASSERT_EQ( - OEMCrypto_SUCCESS, - GenericEncrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(key_handle.data(), key_handle.size(), buffer.data(), + buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + buffer.data())); ASSERT_EQ(expected_encrypted, buffer); } -TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) { - EncryptAndLoadKeys(); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [session_id](size_t key_id_length) { - vector key_id(key_id_length); - return OEMCrypto_SelectKey(session_id, key_id.data(), key_id.size(), - OEMCrypto_CipherMode_CENC); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_P(OEMCryptoGenericCryptoTest, - OEMCryptoMemoryGenericKeyEncryptForHugeBuffer) { - EncryptAndLoadKeys(); - unsigned int key_index = 0; - vector expected_encrypted; - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto& iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { - vector buffer(buffer_length); - return OEMCrypto_Generic_Encrypt(session_id, buffer.data(), buffer.size(), - iv, OEMCrypto_AES_CBC_128_NO_PADDING, - buffer.data()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, - kCheckStatus); -} - TEST_P( OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) { EncryptAndLoadKeys(); unsigned int key_index = 0; vector expected_encrypted; + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - OEMCrypto_SESSION session_id = session_.session_id(); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector buffer(17); ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt( - session_id, buffer.data(), buffer.size(), iv_, + key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); } @@ -7752,43 +3301,21 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { unsigned int key_index = 1; vector encrypted; EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector resultant(encrypted.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericDecrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } -TEST_P(OEMCryptoGenericCryptoTest, - OEMCryptoMemoryGenericKeyDecryptForHugeBuffer) { - EncryptAndLoadKeys(); - unsigned int key_index = 1; - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - OEMCrypto_SESSION session_id = session_.session_id(); - auto iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { - vector encrypted(buffer_length); - vector resultant(encrypted.size()); - - return OEMCrypto_Generic_Decrypt( - session_id, encrypted.data(), encrypted.size(), iv, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); - }; - // API expects length to be multiple of 16. Starting from 16. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, - kCheckStatus); -} - // Test that Generic_Decrypt works correctly when the input and output buffers // are the same. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { @@ -7796,17 +3323,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { unsigned int key_index = 1; vector encrypted; EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector buffer = encrypted; - ASSERT_EQ( - OEMCrypto_SUCCESS, - GenericDecrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericDecrypt(key_handle.data(), key_handle.size(), buffer.data(), + buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + buffer.data())); ASSERT_EQ(clear_buffer_, buffer); } @@ -7820,17 +3348,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) { unsigned int key_index = 1; vector encrypted; EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector resultant(encrypted.size()); - ASSERT_NE( - OEMCrypto_SUCCESS, - GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_NE(OEMCrypto_SUCCESS, + GenericDecrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_NE(clear_buffer_, resultant); } @@ -7851,71 +3380,28 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) { vector expected_signature; SignBuffer(key_index, clear_buffer_, &expected_signature); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, - &gen_signature_length)); + GenericSign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } -TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { - EncryptAndLoadKeys(); - unsigned int key_index = 2; - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - vector signature(SHA256_DIGEST_LENGTH); - size_t signature_length = signature.size(); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &signature, - &signature_length](size_t buffer_length) { - vector buffer(buffer_length); - return OEMCrypto_Generic_Sign(session_id, buffer.data(), buffer.size(), - OEMCrypto_HMAC_SHA256, signature.data(), - &signature_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_P(OEMCryptoGenericCryptoTest, - OEMCryptoMemoryGenericKeySignForHugeSignatureLength) { - EncryptAndLoadKeys(); - unsigned int key_index = 2; - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - 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(session_id, clear_buffer.data(), - clear_buffer.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - // Test that the Generic_Sign function fails when not allowed. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) { EncryptAndLoadKeys(); @@ -7931,61 +3417,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) { vector signature; SignBuffer(key_index, clear_buffer_, &signature); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericVerify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); -} - -TEST_P(OEMCryptoGenericCryptoTest, - OEMCryptoMemoryGenericKeyVerifyForHugeBuffer) { - EncryptAndLoadKeys(); - unsigned int key_index = 3; + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - auto oemcrypto_function = [&](size_t buffer_length) { - vector buffer(buffer_length); - vector signature; - SignBuffer(key_index, buffer, &signature); - return GenericVerify(session_.session_id(), buffer.data(), buffer.size(), - OEMCrypto_HMAC_SHA256, signature.data(), - signature.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_P(OEMCryptoGenericCryptoTest, - OEMCryptoMemoryGenericKeyVerifyForHugeSignatureLength) { - EncryptAndLoadKeys(); - unsigned int key_index = 3; - vector signature; - SignBuffer(key_index, clear_buffer_, &signature); - - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto clear_buffer = clear_buffer_; - auto oemcrypto_function = [&session_id, &clear_buffer, - &signature](size_t signature_length) { - return OEMCrypto_Generic_Verify(session_id, clear_buffer.data(), - clear_buffer.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } // Test that the Generic_Verify function fails when not allowed. @@ -8007,16 +3450,17 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) { unsigned int key_index = 0; vector expected_encrypted; EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector encrypted(clear_buffer_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, - GenericEncrypt(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), iv_, + GenericEncrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -8029,17 +3473,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) { unsigned int key_index = 1; vector encrypted; EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector resultant(encrypted.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericDecrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } @@ -8051,23 +3496,25 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) { vector expected_signature; SignBuffer(key_index, clear_buffer_, &expected_signature); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, - &gen_signature_length)); + GenericSign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } @@ -8079,16 +3526,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) { vector signature; SignBuffer(key_index, clear_buffer_, &signature); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericVerify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } // Test Generic_Encrypt when the key duration has expired. @@ -8102,27 +3551,29 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) { unsigned int key_index = 0; vector encrypted(clear_buffer_.size()); + vector key_handle; // Should be valid key at the start. ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); ASSERT_EQ(OEMCrypto_SUCCESS, - GenericEncrypt(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), iv_, + GenericEncrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. encrypted.assign(clear_buffer_.size(), 0); OEMCryptoResult status = OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()); + key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + encrypted.data()); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); ASSERT_NE(encrypted, expected_encrypted); - ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); + ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index)); } // Test Generic_Decrypt when the key duration has expired. @@ -8136,27 +3587,28 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) { unsigned int key_index = 1; vector encrypted; EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector resultant(encrypted.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericDecrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. resultant.assign(encrypted.size(), 0); - OEMCryptoResult status = - GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + OEMCryptoResult status = GenericDecrypt( + key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); ASSERT_NE(clear_buffer_, resultant); - ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); + ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index)); } // Test Generic_Sign when the key duration has expired. @@ -8172,27 +3624,30 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) { size_t signature_length = signature.size(); SignBuffer(key_index, clear_buffer_, &expected_signature); + vector key_handle; // Should be valid key at the start. ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericSign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &signature_length)); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), + &signature_length)); ASSERT_EQ(expected_signature, signature); wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. signature.assign(SHA256_DIGEST_LENGTH, 0); - OEMCryptoResult status = GenericSign( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - OEMCrypto_HMAC_SHA256, signature.data(), &signature_length); + OEMCryptoResult status = + GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), + &signature_length); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); ASSERT_NE(expected_signature, signature); - ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); + ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index)); } // Test Generic_Verify when the key duration has expired. @@ -8206,24 +3661,27 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) { vector signature; SignBuffer(key_index, clear_buffer_, &signature); + vector key_handle; // Should be valid key at the start. ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); - ASSERT_EQ(OEMCrypto_SUCCESS, - GenericVerify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + GetKeyHandleIntoVector(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. OEMCryptoResult status = OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - OEMCrypto_HMAC_SHA256, signature.data(), signature.size()); + key_handle.data(), key_handle.size(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); - ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); + ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index)); } const unsigned int kLongKeyId = 2; @@ -8277,16 +3735,18 @@ class OEMCryptoGenericCryptoKeyIdLengthTest memcpy(key_id_buffer.data(), session_.license().keys[kLongKeyId].key_id, session_.license().keys[kLongKeyId].key_id_length); EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; ASSERT_EQ( OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(session_.session_id(), key_id_buffer.data(), - session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC)); + GetKeyHandleIntoVector(session_.session_id(), key_id_buffer.data(), + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle)); vector resultant(encrypted.size()); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(), + encrypted.data(), encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, + resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } }; @@ -8321,1873 +3781,4 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest, INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); /// @} - -/// @addtogroup usage_table -/// @{ - -// Test usage table functionality. -class LicenseWithUsageEntry { - public: - LicenseWithUsageEntry(const std::string& pst = "my_pst") - : session_(), - license_messages_(&session_), - generic_crypto_(false), - time_license_received_(0), - time_first_decrypt_(0), - time_last_decrypt_(0), - active_(true) { - license_messages_.set_pst(pst); - } - - void MakeAndLoadOnline(OEMCryptoSessionTests* test) { - MakeAndLoad(test, - wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired); - } - - // If status in not a nullptr, then creating a new entry is allowed to fail, - // and its error code is stored in status. - void MakeOfflineAndClose(OEMCryptoSessionTests* test, - OEMCryptoResult* status = nullptr) { - MakeAndLoad(test, wvoec::kControlNonceOrEntry, status); - if (status != nullptr && *status != OEMCrypto_SUCCESS) { - ASSERT_NO_FATAL_FAILURE(session_.close()); - return; - } - ASSERT_NO_FATAL_FAILURE( - session_.UpdateUsageEntry(&(test->encrypted_usage_header_))); - ASSERT_NO_FATAL_FAILURE(GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(session_.close()); - } - - // If status in not a nullptr, then creating a new entry is allowed to fail, - // and its error code is stored in status. - void MakeAndLoad(SessionUtil* util, uint32_t control, - OEMCryptoResult* status = nullptr) { - license_messages_.set_control(control); - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(&session_)); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - if (generic_crypto_) { - ASSERT_NO_FATAL_FAILURE( - license_messages_.CreateResponseWithGenericCryptoKeys()); - } else { - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - } - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry(status)); - if (status != nullptr && *status != OEMCrypto_SUCCESS) return; - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - time_license_received_ = wvutil::Clock().GetCurrentTime(); - } - - void OpenAndReload(SessionUtil* util) { - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(session_.ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(&session_)); - ASSERT_NO_FATAL_FAILURE(session_.GenerateDerivedKeysFromSessionKey()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - } - - // Test decrypt, and update the decrypt times for the pst report. - void TestDecryptCTR(bool select_key_first = true, - OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { - session_.TestDecryptCTR(select_key_first, expected_result); - time_last_decrypt_ = wvutil::Clock().GetCurrentTime(); - if (time_first_decrypt_ == 0) time_first_decrypt_ = time_last_decrypt_; - } - - void DeactivateUsageEntry() { - active_ = false; - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_deactivate_usage_entry_fuzz_seed_corpus"); - AppendToFile(file_name, pst().c_str(), pst().length()); - } - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_DeactivateUsageEntry( - session_.session_id(), - reinterpret_cast(pst().c_str()), pst().length())); - } - - void GenerateVerifyReport(OEMCrypto_Usage_Entry_Status status) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateReport(pst())); - Test_PST_Report expected(pst(), status); - ASSERT_NO_FATAL_FAILURE( - session_.VerifyReport(expected, time_license_received_, - time_first_decrypt_, time_last_decrypt_)); - // The PST report was signed above. Below we verify that the entire message - // that is sent to the server will be signed by the right mac keys. - RenewalRoundTrip renewal_messages(&license_messages_); - renewal_messages.set_is_release(!active_); - ASSERT_NO_FATAL_FAILURE(renewal_messages.SignAndVerifyRequest()); - } - - void ReloadUsageEntry() { - session_.ReloadUsageEntry(); - session_.set_mac_keys(license_messages_.response_data().mac_keys); - } - - const std::string& pst() const { return license_messages_.pst(); } - void set_pst(const std::string& pst) { license_messages_.set_pst(pst); } - LicenseRoundTrip& license_messages() { return license_messages_; } - Session& session() { return session_; } - void set_generic_crypto(bool generic_crypto) { - generic_crypto_ = generic_crypto; - } - - private: - Session session_; - LicenseRoundTrip license_messages_; - bool generic_crypto_; - int64_t time_license_received_; - int64_t time_first_decrypt_; - int64_t time_last_decrypt_; - bool active_; -}; - -class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { - public: - void SetUp() override { OEMCryptoGenericCryptoTest::SetUp(); } - - virtual void ShutDown() { - ASSERT_NO_FATAL_FAILURE(session_.close()); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); - } - - virtual void Restart() { - OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); - EnsureTestKeys(); - ASSERT_NO_FATAL_FAILURE(session_.open()); - } - - void PrintDotsWhileSleep(int64_t total_seconds, int64_t interval_seconds) { - int64_t dot_time = interval_seconds; - int64_t elapsed_time = 0; - const int64_t start_time = wvutil::Clock().GetCurrentTime(); - do { - wvutil::TestSleep::Sleep(1); - elapsed_time = wvutil::Clock().GetCurrentTime() - start_time; - if (elapsed_time >= dot_time) { - cout << "."; - cout.flush(); - dot_time += interval_seconds; - } - } while (elapsed_time < total_seconds); - cout << endl; - } - - OEMCryptoResult LoadUsageTableHeader( - const vector& encrypted_usage_header) { - return OEMCrypto_LoadUsageTableHeader(encrypted_usage_header.data(), - encrypted_usage_header.size()); - } -}; - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryUpdateUsageEntryForHugeHeaderBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - if (buffer_length < encrypted_usage_header_.size()) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - size_t header_buffer_length = 0; - size_t entry_buffer_length = 0; - // Header buffer length varies as generation_numbers size changes on every - // call. Hence, we need to call update usage entry in every loop to get - // latest value of header_buffer_length. - OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, - nullptr, &entry_buffer_length); - vector encrypted_usage_entry(entry_buffer_length); - vector header_buffer(encrypted_usage_header_); - header_buffer.resize(buffer_length); - return OEMCrypto_UpdateUsageEntry( - s.session_id(), header_buffer.data(), &buffer_length, - encrypted_usage_entry.data(), &entry_buffer_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryUpdateUsageEntryForHugeUsageEntryBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - size_t header_buffer_length = 0; - size_t entry_buffer_length = 0; - // Header buffer length varies as generation_numbers size changes on every - // call. Hence, we need to call update usage entry in every loop to get - // latest value of header_buffer_length. - OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, - nullptr, &entry_buffer_length); - vector header_buffer(encrypted_usage_header_); - header_buffer.resize(header_buffer_length); - vector encrypted_usage_entry(buffer_length); - return OEMCrypto_UpdateUsageEntry( - s.session_id(), header_buffer.data(), &header_buffer_length, - encrypted_usage_entry.data(), &buffer_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryDeactivateUsageEntryForHugePstBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - std::string pst("pst"); - pst.resize(buffer_length); - entry.license_messages().set_pst(pst); - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - return OEMCrypto_DeactivateUsageEntry( - s.session_id(), reinterpret_cast(pst.c_str()), - pst.length()); - }; - // The test setup assertions fails if pst length goes beyond kMaxPSTLength. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, kMaxPSTLength, - kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryLoadUsageTableHeaderForHugeHeader) { - auto oemcrypto_function = [&](size_t buffer_length) { - if (buffer_length < encrypted_usage_header_.size()) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - vector header_buffer(encrypted_usage_header_); - header_buffer.resize(buffer_length); - return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), - header_buffer.size()); - }; - // We cannot generate an encrypted usage header of varying length with - // valid signature. Hence irrespective of return status, we call API for - // varying buffer lengths. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, - encrypted_usage_header_.size(), - kHugeInputBufferLength, !kCheckStatus); -} - -TEST_P( - OEMCryptoUsageTableTest, - OEMCryptoMemoryLoadUsageTableHeaderForHugeHeaderStartingHeaderLengthFrom1) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - vector header_buffer(buffer_length); - return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), - header_buffer.size()); - }; - // We cannot generate an encrypted usage header of varying length with - // valid signature. Hence irrespective of return status, we call API for - // varying buffer lengths. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryLoadUsageEntryForHugeUsageEntryBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - Session& s = entry.session(); - // Make first entry 0. - entry.MakeOfflineAndClose(this); - if (buffer_length < s.encrypted_usage_entry().size()) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - Session s2; - s2.open(); - InstallTestRSAKey(&s2); - vector encrypted_usage_entry(buffer_length); - memcpy(encrypted_usage_entry.data(), s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size()); - const uint32_t usage_entry_number = s.usage_entry_number(); - return OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, - encrypted_usage_entry.data(), - encrypted_usage_entry.size()); - }; - // We cannot generate an encrypted usage enctry of varying length with - // valid signature. Hence irrespective of return status, we call API for - // varying buffer lengths. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryLoadUsageEntryForHugeInvalidUsageEntryNumber) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - // Make first entry 0. - entry.MakeOfflineAndClose(this); - Session s; - s.open(); - InstallTestRSAKey(&s); - const uint32_t usage_entry_number = kHugeRandomNumber; - ASSERT_NO_FATAL_FAILURE(OEMCrypto_LoadUsageEntry( - s.session_id(), usage_entry_number, s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); -} - -TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - s.UpdateUsageEntry(&encrypted_usage_header_); - size_t length = 0; - OEMCrypto_ReportUsage(s.session_id(), - reinterpret_cast(entry.pst().c_str()), - entry.pst().length(), nullptr, &length); - if (ShouldGenerateCorpus()) { - const std::string file_name = - GetFileName("oemcrypto_report_usage_fuzz_seed_corpus"); - AppendToFile(file_name, reinterpret_cast(&length), - sizeof(length)); - AppendToFile(file_name, entry.pst().c_str(), entry.pst().length()); - } - vector pst_report_buffer(buffer_length); - return OEMCrypto_ReportUsage( - s.session_id(), reinterpret_cast(entry.pst().c_str()), - entry.pst().length(), pst_report_buffer.data(), &buffer_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - s.UpdateUsageEntry(&encrypted_usage_header_); - size_t length = 0; - OEMCrypto_ReportUsage(s.session_id(), - reinterpret_cast(entry.pst().c_str()), - entry.pst().length(), nullptr, &length); - vector pst_report_buffer(length); - vector pst(buffer_length); - return OEMCrypto_ReportUsage(s.session_id(), pst.data(), pst.size(), - pst_report_buffer.data(), &length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); -} - -TEST_P(OEMCryptoUsageTableTest, - OEMCryptoMemoryShrinkUsageTableHeaderForHugeHeaderBufferLength) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - auto oemcrypto_function = [&](size_t buffer_length) { - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - size_t header_buffer_length = buffer_length; - encrypted_usage_header_.resize(header_buffer_length); - return OEMCrypto_ShrinkUsageTableHeader(1, encrypted_usage_header_.data(), - &header_buffer_length); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -// Test an online or streaming license with PST. This license requires a valid -// nonce and can only be loaded once. -TEST_P(OEMCryptoUsageTableTest, OnlineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - - // test repeated report generation - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - // Flag the entry as inactive. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // It should report as inactive. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - // Decrypt should fail. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - // We could call DeactivateUsageEntry multiple times. The state should not - // change. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // It should report as inactive. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); -} - -// Test the usage report when the license is loaded but the keys are never used -// for decryption. -TEST_P(OEMCryptoUsageTableTest, OnlineLicenseUnused) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // No decrypt. We do not use this license. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - // Flag the entry as inactive. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // It should report as inactive. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); - // Decrypt should fail. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - // We could call DeactivateUsageEntry multiple times. The state should not - // change. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // It should report as inactive. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); -} - -// Test that the usage table has been updated and saved before a report can be -// generated. -TEST_P(OEMCryptoUsageTableTest, ForbidReportWithNoUpdate) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - // Cannot generate a report without first updating the file. - ASSERT_NO_FATAL_FAILURE( - s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // Now it's OK. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - // Flag the entry as inactive. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - // Cannot generate a report without first updating the file. - ASSERT_NO_FATAL_FAILURE( - s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE)); - // Decrypt should fail. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// Test an online license with a license renewal. -TEST_P(OEMCryptoUsageTableTest, OnlineLicenseWithRefreshAPI16) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - - RenewalRoundTrip renewal_messages(&entry.license_messages()); - MakeRenewalRequest(&renewal_messages); - LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); -} - -// Verify that a streaming license cannot be reloaded. -TEST_P(OEMCryptoUsageTableTest, RepeatOnlineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s.close()); - Session s2; - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s2)); - s2.LoadUsageEntry(s); // Use the same entry. - ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s2)); -} - -// An offline license should not load on the first call if the nonce is bad. -TEST_P(OEMCryptoUsageTableTest, OnlineBadNonce) { - Session s; - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - license_messages.set_control(wvoec::kControlNonceEnabled | - wvoec::kControlNonceRequired); - license_messages.set_pst("my-pst"); - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - for (uint32_t i = 0; i < license_messages.num_keys(); i++) - license_messages.response_data().keys[i].control.nonce ^= 42; - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); -} - -// A license with non-zero replay control bits needs a valid pst. -TEST_P(OEMCryptoUsageTableTest, OnlineEmptyPST) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - license_messages.set_control(wvoec::kControlNonceEnabled | - wvoec::kControlNonceRequired); - // DO NOT SET PST: license_messages.set_pst(pst); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); -} - -// A license with non-zero replay control bits needs a valid pst. -TEST_P(OEMCryptoUsageTableTest, OnlineMissingEntry) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - license_messages.set_control(wvoec::kControlNonceEnabled | - wvoec::kControlNonceRequired); - license_messages.set_pst("my-pst"); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - // ENTRY NOT CREATED: ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); -} - -// Sessions should have at most one entry at a time. This tests different -// orderings of CreateNewUsageEntry and LoadUsageEntry calls. -TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { - // Entry Count: we start each test with an empty header. - uint32_t usage_entry_number; - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - Session& s = entry.session(); - // Make first entry 0. - ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); - - // Load an entry, then try to create a second. - ASSERT_NO_FATAL_FAILURE(s.open()); - // Reload entry 0. - ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); - // Create new entry 1 should fail. - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_CreateNewUsageEntry(entry.session().session_id(), - &usage_entry_number)); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Create an entry, then try to load a second. - Session s2; - ASSERT_NO_FATAL_FAILURE(s2.open()); - // Create entry 1. - ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); - // Try to reload entry 0. - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageEntry(s2.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - ASSERT_NO_FATAL_FAILURE(s2.close()); - - // Reload an entry and a license, then try to load the same entry again. - // This reloads entry 0. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Create an entry, then try to create a second entry. - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry( - s2.session_id(), &usage_entry_number)); -} - -// An entry can be loaded in only one session at a time. -TEST_P(OEMCryptoUsageTableTest, LoadEntryInMultipleSessions) { - // Entry Count: we start each test with an empty header. - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - Session& s = entry.session(); - // Make first entry 0. - ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); - const uint32_t usage_entry_number = s.usage_entry_number(); - EXPECT_EQ(usage_entry_number, 0u); // Should be only entry in this test. - - // Load an entry, then try to create a second. - ASSERT_NO_FATAL_FAILURE(s.open()); - // Reload entry 0. - ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); - - // Create an entry, then try to load a second. - Session s2; - ASSERT_NO_FATAL_FAILURE(s2.open()); - // Try to load entry 0 into session 2. - ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, - OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); -} - -// Test generic encrypt when the license uses a PST. -TEST_P(OEMCryptoUsageTableTest, GenericCryptoEncrypt) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.set_generic_crypto(true); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - OEMCryptoResult sts; - unsigned int key_index = 0; - vector expected_encrypted; - EncryptBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, - &expected_encrypted); - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - vector encrypted(clear_buffer_.size()); - sts = OEMCrypto_Generic_Encrypt( - s.session_id(), clear_buffer_.data(), clear_buffer_.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - EXPECT_EQ(expected_encrypted, encrypted); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - encrypted.assign(clear_buffer_.size(), 0); - sts = OEMCrypto_Generic_Encrypt( - s.session_id(), clear_buffer_.data(), clear_buffer_.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(encrypted, expected_encrypted); -} - -// Test generic decrypt when the license uses a PST. -TEST_P(OEMCryptoUsageTableTest, GenericCryptoDecrypt) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.set_generic_crypto(true); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - OEMCryptoResult sts; - unsigned int key_index = 1; - vector encrypted; - EncryptBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, - &encrypted); - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - vector resultant(encrypted.size()); - sts = OEMCrypto_Generic_Decrypt( - s.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - EXPECT_EQ(clear_buffer_, resultant); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - resultant.assign(encrypted.size(), 0); - sts = OEMCrypto_Generic_Decrypt( - s.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - EXPECT_NE(clear_buffer_, resultant); -} - -// Test generic sign when the license uses a PST. -TEST_P(OEMCryptoUsageTableTest, GenericCryptoSign) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.set_generic_crypto(true); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - OEMCryptoResult sts; - unsigned int key_index = 2; - vector expected_signature; - SignBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, - &expected_signature); - - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - size_t gen_signature_length = 0; - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - nullptr, &gen_signature_length); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); - vector signature(SHA256_DIGEST_LENGTH); - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(expected_signature, signature); - - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - signature.assign(SHA256_DIGEST_LENGTH, 0); - gen_signature_length = SHA256_DIGEST_LENGTH; - sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length); - ASSERT_NE(OEMCrypto_SUCCESS, sts); - ASSERT_NE(signature, expected_signature); -} - -// Test generic verify when the license uses a PST. -TEST_P(OEMCryptoUsageTableTest, GenericCryptoVerify) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.set_generic_crypto(true); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - OEMCryptoResult sts; - unsigned int key_index = 3; - vector signature; - SignBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, - &signature); - - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size()); - ASSERT_NE(OEMCrypto_SUCCESS, sts); -} - -// Test that an offline license can be loaded. -TEST_P(OEMCryptoUsageTableTest, OfflineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); -} - -// Test that an offline license can be loaded and that the license can be -// renewed. -TEST_P(OEMCryptoUsageTableTest, OfflineLicenseRefresh) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoad(this, wvoec::kControlNonceOrEntry); - Session& s = entry.session(); - - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - // License renewal message is signed by client and verified by the server. - RenewalRoundTrip renewal_messages(&entry.license_messages()); - MakeRenewalRequest(&renewal_messages); - LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); -} - -// Test that an offline license can be reloaded in a new session. -TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); -} - -// Test that an offline license can be reloaded in a new session, and then -// refreshed. -TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithRefresh) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - RenewalRoundTrip renewal_messages(&entry.license_messages()); - MakeRenewalRequest(&renewal_messages); - LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); -} - -// Verify that we can still reload an offline license after OEMCrypto_Terminate -// and Initialize are called. This is as close to a reboot as we can do in a -// unit test. -TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithTerminate) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - ShutDown(); // This calls OEMCrypto_Terminate. - Restart(); // This calls OEMCrypto_Initialize. - ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); - - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); -} - -// If we attempt to load a second license with the same usage entry as the -// first, but it has different mac keys, then the attempt should fail. This is -// how we verify that we are reloading the same license. -TEST_P(OEMCryptoUsageTableTest, BadReloadOfflineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - - // Offline license with new mac keys should fail. - Session s2; - LicenseRoundTrip license_messages2(&s2); - // Copy the response, and then change the mac keys. - license_messages2.response_data() = entry.license_messages().response_data(); - license_messages2.core_response() = entry.license_messages().core_response(); - license_messages2.response_data().mac_keys[7] ^= 42; - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s2)); - // This is a valid license: it is correctly signed. - license_messages2.EncryptAndSignResponse(); - // Load the usage entry should be OK. - ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages2.LoadResponse()); - ASSERT_NO_FATAL_FAILURE(s2.close()); - - // Now we go back to the original license response. It should load OK. - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); -} - -// An offline license should not load on the first call if the nonce is bad. -TEST_P(OEMCryptoUsageTableTest, OfflineBadNonce) { - Session s; - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - license_messages.set_control(wvoec::kControlNonceOrEntry); - license_messages.set_pst("my-pst"); - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - for (size_t i = 0; i < license_messages.num_keys(); i++) - license_messages.response_data().keys[i].control.nonce ^= 42; - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); -} - -// An offline license needs a valid pst. -TEST_P(OEMCryptoUsageTableTest, OfflineEmptyPST) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - license_messages.set_control(wvoec::kControlNonceOrEntry); - // DO NOT SET PST: license_messages.set_pst(pst); - ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); - ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); -} - -// If we try to reload a license with a different PST, the attempt should fail. -TEST_P(OEMCryptoUsageTableTest, ReloadOfflineWrongPST) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - - Session s2; - LicenseRoundTrip license_messages2(&s2); - license_messages2.response_data() = entry.license_messages().response_data(); - license_messages2.core_response() = entry.license_messages().core_response(); - // Change the middle of the pst. - license_messages2.response_data().pst[3] ^= 'Z'; - ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s2)); - // This is a valid license: it is correctly signed. - license_messages2.EncryptAndSignResponse(); - // Load the usage entry should be OK. - ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages2.LoadResponse()); -} - -// Once a license has been deactivated, the keys can no longer be used for -// decryption. However, we can still generate a usage report. -TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicense) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - // Reload the offline license. - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR()); // Should be able to decrypt. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. - // After deactivate, should not be able to decrypt. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Offline license can not be reused if it has been deactivated. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); - s.close(); - - // But we can still generate a report. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // Sending a release from an offline license that has been deactivate will - // only work if the license server can handle v16 licenses. This is a rare - // condition, so it is OK to break it during the transition months. - entry.license_messages().set_api_version(global_features.api_version); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - // We could call DeactivateUsageEntry multiple times. The state should not - // change. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); -} - -// The usage report should indicate that the keys were never used for -// decryption. -TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicenseUnused) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - // No Decrypt. This license is unused. - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. - // After deactivate, should not be able to decrypt. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Offline license can not be reused if it has been deactivated. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); - s.close(); - - // But we can still generate a report. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // Sending a release from an offline license that has been deactivate will - // only work if the license server can handle v16 licenses. This is a rare - // condition, so it is OK to break it during the transition months. - entry.license_messages().set_api_version(global_features.api_version); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); - // We could call DeactivateUsageEntry multiple times. The state should not - // change. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); -} - -TEST_P(OEMCryptoUsageTableTest, SecureStop) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s.close()); - // When we generate a secure stop without loading the license first, it - // should assume the server does not support core messages. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - // It should report as inactive. - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); -} - -// Test update usage table fails when passed a null pointer. -TEST_P(OEMCryptoUsageTableTest, UpdateFailsWithNullPtr) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - size_t header_buffer_length = encrypted_usage_header_.size(); - size_t entry_buffer_length = s.encrypted_usage_entry().size(); - vector buffer(entry_buffer_length); - // Now try to pass in null pointers for the buffers. This should fail. - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, - buffer.data(), &entry_buffer_length)); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_UpdateUsageEntry( - s.session_id(), encrypted_usage_header_.data(), - &header_buffer_length, nullptr, &entry_buffer_length)); -} - -// Class used to test usage table defragmentation. -class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest { - protected: - void ReloadLicense(LicenseWithUsageEntry* entry) { - Session& s = entry->session(); - ASSERT_NO_FATAL_FAILURE(entry->OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry->TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry->GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(s.close()); - } - - void FailReloadLicense(LicenseWithUsageEntry* entry, - OEMCryptoResult expected_result) { - Session& s = entry->session(); - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_EQ(expected_result, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - - ASSERT_NE(OEMCrypto_SUCCESS, entry->license_messages().LoadResponse()); - ASSERT_NO_FATAL_FAILURE(s.close()); - } - - void ShrinkHeader(uint32_t new_size, - OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { - // We call OEMCrypto_ShrinkUsageTableHeader once with a zero length buffer, - // so that OEMCrypto can tell us how big the buffer should be. - size_t header_buffer_length = 0; - OEMCryptoResult sts = OEMCrypto_ShrinkUsageTableHeader( - new_size, nullptr, &header_buffer_length); - // If we are expecting success, then the first call shall return - // SHORT_BUFFER. However, if we are not expecting success, this first call - // may return either SHORT_BUFFER or the expect error. - if (expected_result == OEMCrypto_SUCCESS) { - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - } else if (sts != OEMCrypto_ERROR_SHORT_BUFFER) { - // If we got any thing from the first call, it should be the expected - // error, and we don't need to call a second time. - ASSERT_EQ(expected_result, sts); - return; - } - // If the first call resulted in SHORT_BUFFER, we should resize the buffer - // and try again. - ASSERT_LT(0u, header_buffer_length); - encrypted_usage_header_.resize(header_buffer_length); - sts = OEMCrypto_ShrinkUsageTableHeader( - new_size, encrypted_usage_header_.data(), &header_buffer_length); - // For the second call, we always demand the expected result. - ASSERT_EQ(expected_result, sts); - if (sts == OEMCrypto_SUCCESS) { - encrypted_usage_header_.resize(header_buffer_length); - } - } -}; - -// Verify that usage table entries can be moved around in the table. -TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { - const size_t ENTRY_COUNT = 10; - vector entries(ENTRY_COUNT); - for (size_t i = 0; i < ENTRY_COUNT; i++) { - entries[i].set_pst("pst " + std::to_string(i)); - ASSERT_NO_FATAL_FAILURE(entries[i].MakeOfflineAndClose(this)) - << "On license " << i << " pst=" << entries[i].pst(); - wvutil::TestSleep::SyncFakeClock(); - } - for (size_t i = 0; i < ENTRY_COUNT; i++) { - ASSERT_NO_FATAL_FAILURE(entries[i].OpenAndReload(this)) - << "On license " << i << " pst=" << entries[i].pst(); - ASSERT_NO_FATAL_FAILURE(entries[i].session().close()) - << "On license " << i << " pst=" << entries[i].pst(); - } - // Move 4 to 1. - ASSERT_NO_FATAL_FAILURE( - entries[4].session().MoveUsageEntry(1, &encrypted_usage_header_)); - // Shrink header to 3 entries 0, 1 was 4, 2. - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(3)); - ShutDown(); - Restart(); - ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); - wvutil::TestSleep::SyncFakeClock(); - ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0])); - // Now has index 1. - ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[4])); - ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[2])); - // When 4 was moved to 1, it increased the gen. number in the header. - ASSERT_NO_FATAL_FAILURE( - FailReloadLicense(&entries[1], OEMCrypto_ERROR_GENERATION_SKEW)); - // Index 3 is beyond the end of the table. - ASSERT_NO_FATAL_FAILURE( - FailReloadLicense(&entries[3], OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// A usage table entry cannot be moved into an entry where an open session is -// currently using the entry. -TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToOpenSession) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); - // s0 currently open on index 0. Expect this to fail: - ASSERT_NO_FATAL_FAILURE(entry1.session().MoveUsageEntry( - 0, &encrypted_usage_header_, OEMCrypto_ERROR_ENTRY_IN_USE)); -} - -TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToInvalidHugeEntryIndex) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - entry0.session().open(); - entry0.ReloadUsageEntry(); - ASSERT_NO_FATAL_FAILURE( - OEMCrypto_MoveEntry(entry0.session().session_id(), kHugeRandomNumber)); -} - -// The usage table cannot be shrunk if any session is using an entry that would -// be deleted. -TEST_P(OEMCryptoUsageTableDefragTest, ShrinkOverOpenSessions) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); - entry1.session().open(); - ASSERT_NO_FATAL_FAILURE(entry1.ReloadUsageEntry()); - // Since s0 and s1 are open, we can't shrink. - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(1, OEMCrypto_ERROR_ENTRY_IN_USE)); - entry1.session().close(); // Can shrink after closing s1, even if s0 is open. - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(1, OEMCrypto_SUCCESS)); -} - -// Verify the usage table size can be increased. -TEST_P(OEMCryptoUsageTableDefragTest, EnlargeHeader) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - - // Can only shrink the header -- not make it bigger. - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(4, OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// A new header can only be created while no entries are in use. -TEST_P(OEMCryptoUsageTableDefragTest, CreateNewHeaderWhileUsingOldOne) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); - const bool kExpectFailure = false; - ASSERT_NO_FATAL_FAILURE(CreateUsageTableHeader(kExpectFailure)); -} - -// Verify that a usage table entry can only be loaded into the correct index of -// the table. -TEST_P(OEMCryptoUsageTableDefragTest, ReloadUsageEntryWrongIndex) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - entry0.MakeOfflineAndClose(this); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - entry1.MakeOfflineAndClose(this); - - entry0.session().set_usage_entry_number(1); - ASSERT_NO_FATAL_FAILURE( - FailReloadLicense(&entry0, OEMCrypto_ERROR_INVALID_SESSION)); -} - -// Verify that a usage table entry cannot be loaded if it has been altered. -TEST_P(OEMCryptoUsageTableDefragTest, ReloadUsageEntryBadData) { - LicenseWithUsageEntry entry; - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - vector data = s.encrypted_usage_entry(); - ASSERT_LT(0UL, data.size()); - data[0] ^= 42; - // Error could be signature or verification error. - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - data.data(), data.size())); -} - -// This verifies we can actually create the required number of usage table -// entries. -TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { - // OEMCrypto is required to store at least 300 entries in the usage table - // header, but it is allowed to store more. This test verifies that if we keep - // adding entries, the error indicates a resource limit. It then verifies - // that all of the successful entries are still valid after we throw out the - // last invalid entry. - - // After API 16, we require 300 entries in the usage table. Before API 16, we - // required 200. - const size_t required_capacity = RequiredUsageSize(); - - // We try to make a much large header, and assume there is an error at some - // point. - const size_t attempt_count = required_capacity * 5; - // Count of how many entries we successfully create. - size_t successful_count = 0; - - // These entries have licenses tied to them. - std::vector> entries; - // Store the status of the last attempt to create an entry. - OEMCryptoResult status = OEMCrypto_SUCCESS; - while (successful_count < attempt_count && status == OEMCrypto_SUCCESS) { - wvutil::TestSleep::SyncFakeClock(); - LOGD("Creating license for entry %zu", successful_count); - entries.push_back( - std::unique_ptr(new LicenseWithUsageEntry())); - entries.back()->set_pst("pst " + std::to_string(successful_count)); - ASSERT_NO_FATAL_FAILURE(entries.back()->MakeOfflineAndClose(this, &status)) - << "Failed creating license for entry " << successful_count; - if (status != OEMCrypto_SUCCESS) { - // Remove the failed session. - entries.resize(entries.size() - 1); - break; - } - EXPECT_EQ(entries.back()->session().usage_entry_number(), successful_count); - successful_count++; - // We don't create a license for each entry. For every license, we'll - // create 10 empty entries. - constexpr size_t filler_count = 10; - for (size_t i = 0; i < filler_count; i++) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry(&status)) - << "Failed creating entry " << successful_count; - if (status != OEMCrypto_SUCCESS) break; - EXPECT_EQ(s.usage_entry_number(), successful_count); - successful_count++; - } - } - LOGD("successful_count = %zu", successful_count); - if (status != OEMCrypto_SUCCESS) { - // If we failed to create this many entries because of limited resources, - // then the error returned should be insufficient resources. - EXPECT_EQ(OEMCrypto_ERROR_INSUFFICIENT_RESOURCES, status) - << "Failed to create license " << successful_count - << ", with wrong error code."; - } - EXPECT_GE(successful_count, required_capacity); - wvutil::TestSleep::SyncFakeClock(); - // Shrink the table a little. - constexpr size_t small_number = 5; - size_t smaller_size = successful_count - small_number; - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(static_cast(smaller_size))); - // Throw out the last license if it was in the part of the table that was - // shrunk. - if (entries.back()->session().usage_entry_number() >= smaller_size) { - entries.pop_back(); - } - // Create a few more license - for (size_t i = 0; i < small_number; i++) { - wvutil::TestSleep::SyncFakeClock(); - entries.push_back( - std::unique_ptr(new LicenseWithUsageEntry())); - entries.back()->set_pst("new pst " + std::to_string(smaller_size + i)); - entries.back()->MakeOfflineAndClose(this); - } - // Make sure that all of the licenses can be reloaded. - for (size_t i = 0; i < entries.size(); i++) { - wvutil::TestSleep::SyncFakeClock(); - Session& s = entries[i]->session(); - ASSERT_NO_FATAL_FAILURE(entries[i]->OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kUnused)); - ASSERT_NO_FATAL_FAILURE(entries[i]->TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(s.close()); - } -} - -// Verify that usage entries can be created in the position of existing entry -// indexes. -TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryAPI17) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); - const uint32_t number = entry0.session().usage_entry_number(); - entry0.session().close(); - entry1.session().open(); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); -} - -// Verify that usage entries cannot replace an entry that is currently in -// use by a session. -TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryIndexInUseAPI17) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); - const uint32_t number = entry0.session().usage_entry_number(); - entry1.session().open(); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, - OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); -} - -// Verify that usage entries cannot be created if the usage entry index is -// too large. -TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryWithInvalidIndexAPI17) { - LicenseWithUsageEntry entry0; - entry0.set_pst("pst 0"); - LicenseWithUsageEntry entry1; - entry1.set_pst("pst 1"); - - entry0.session().open(); - ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); - const uint32_t number = entry0.session().usage_entry_number(); - entry0.session().close(); - entry1.session().open(); - ASSERT_EQ( - OEMCrypto_ERROR_UNKNOWN_FAILURE, - OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number + 42)); -} - -// Verify that usage entries cannot be created if the session already has an -// entry. -TEST_P(OEMCryptoUsageTableDefragTest, - ReuseUsageEntrySessionAlreadyHasEntryAPI17) { - LicenseWithUsageEntry entry; - entry.set_pst("pst 0"); - - // Create 5 entries in the table. - for (int i = 0; i < 5; i++) { - entry.session().open(); - ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); - entry.session().close(); - } - entry.session().open(); - ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); - const uint32_t number = entry.session().usage_entry_number(); - ASSERT_EQ( - OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, - OEMCrypto_ReuseUsageEntry(entry.session().session_id(), number - 3)); -} - -// This verifies that the usage table header can be loaded if the generation -// number is off by one, but not off by two. -TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { - // This also tests a few other error conditions with usage table headers. - LicenseWithUsageEntry entry; - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - - // Reload the license, and save the header. - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - vector old_usage_header_2_ = encrypted_usage_header_; - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - vector old_usage_header_1_ = encrypted_usage_header_; - vector old_usage_entry_1 = s.encrypted_usage_entry(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s.close()); - - ShutDown(); - Restart(); - // Null pointer generates error. - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageTableHeader( - nullptr, old_usage_header_2_.size())); - ASSERT_NO_FATAL_FAILURE(s.open()); - // Cannot load an entry if header didn't load. - ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Modified header generates error. - vector bad_header = encrypted_usage_header_; - bad_header[3] ^= 42; - ASSERT_NE(OEMCrypto_SUCCESS, LoadUsageTableHeader(bad_header)); - ASSERT_NO_FATAL_FAILURE(s.open()); - // Cannot load an entry if header didn't load. - ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Old by 2 generation numbers is error. - ASSERT_EQ(OEMCrypto_ERROR_GENERATION_SKEW, - LoadUsageTableHeader(old_usage_header_2_)); - ASSERT_NO_FATAL_FAILURE(s.open()); - // Cannot load an entry if header didn't load. - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - s.encrypted_usage_entry().data(), - s.encrypted_usage_entry().size())); - ASSERT_NO_FATAL_FAILURE(s.close()); - - // Old by 1 generation numbers is just warning. - ASSERT_EQ(OEMCrypto_WARNING_GENERATION_SKEW, - LoadUsageTableHeader(old_usage_header_1_)); - // Everything else should still work. The old entry goes with the old header. - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), - old_usage_entry_1.data(), - old_usage_entry_1.size())); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey()); - ASSERT_EQ(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse()); -} - -TEST_P(OEMCryptoUsageTableTest, LoadAndReloadEntries) { - constexpr size_t kEntryCount = 10; - std::vector entries(kEntryCount); - - for (LicenseWithUsageEntry& entry : entries) { - entry.license_messages().set_api_version(license_api_version_); - } - - for (size_t i = 0; i < kEntryCount; ++i) { - const std::string create_description = - "Creating entry #" + std::to_string(i); - // Create and update a new entry. - LicenseWithUsageEntry& new_entry = entries[i]; - ASSERT_NO_FATAL_FAILURE(new_entry.MakeOfflineAndClose(this)) - << create_description; - // Reload all entries, starting with the most recently created. - for (size_t j = 0; j <= i; ++j) { - const std::string reload_description = - "Reloading entry #" + std::to_string(i - j) + - ", after creating entry #" + std::to_string(i); - LicenseWithUsageEntry& old_entry = entries[i - j]; - ASSERT_NO_FATAL_FAILURE(old_entry.session().open()); - ASSERT_NO_FATAL_FAILURE(old_entry.ReloadUsageEntry()) - << reload_description; - ASSERT_NO_FATAL_FAILURE( - old_entry.session().UpdateUsageEntry(&encrypted_usage_header_)) - << reload_description; - ASSERT_NO_FATAL_FAILURE(old_entry.session().close()); - } - } -} - -// A usage report with the wrong pst should fail. -TEST_P(OEMCryptoUsageTableTest, GenerateReportWrongPST) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE( - s.GenerateReport("wrong_pst", OEMCrypto_ERROR_WRONG_PST)); -} - -// Test usage table timing. -TEST_P(OEMCryptoUsageTableTest, TimingTest) { - LicenseWithUsageEntry entry1; - entry1.license_messages().set_api_version(license_api_version_); - Session& s1 = entry1.session(); - entry1.set_pst("my_pst_1"); - ASSERT_NO_FATAL_FAILURE(entry1.MakeOfflineAndClose(this)); - - LicenseWithUsageEntry entry2; - entry2.license_messages().set_api_version(license_api_version_); - Session& s2 = entry2.session(); - entry2.set_pst("my_pst_2"); - ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this)); - - LicenseWithUsageEntry entry3; - entry3.license_messages().set_api_version(license_api_version_); - Session& s3 = entry3.session(); - entry3.set_pst("my_pst_3"); - ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this)); - - ASSERT_NO_FATAL_FAILURE(entry1.MakeOfflineAndClose(this)); - ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this)); - ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this)); - - wvutil::TestSleep::Sleep(kLongSleep); - ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - - ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); - - wvutil::TestSleep::Sleep(kLongSleep); - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); - - wvutil::TestSleep::Sleep(kLongSleep); - ASSERT_NO_FATAL_FAILURE(entry1.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s1.close()); - ASSERT_NO_FATAL_FAILURE(s2.close()); - - wvutil::TestSleep::Sleep(kLongSleep); - // This is as close to reboot as we can simulate in code. - ShutDown(); - wvutil::TestSleep::Sleep(kShortSleep); - Restart(); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), - encrypted_usage_header_.size())); - - // After a reboot, we should be able to reload keys, and generate reports. - wvutil::TestSleep::Sleep(kLongSleep); - ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s2.close()); - - ASSERT_NO_FATAL_FAILURE(s1.open()); - ASSERT_NO_FATAL_FAILURE(entry1.ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE(entry3.OpenAndReload(this)); - - wvutil::TestSleep::Sleep(kLongSleep); - ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry1.GenerateVerifyReport(kInactiveUsed)); - ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry2.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(s3.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry3.GenerateVerifyReport(kUnused)); -} - -// Verify the times in the usage report. For performance reasons, we allow the -// times in the usage report to be off by as much as kUsageTimeTolerance, which -// is 10 seconds. This acceptable error is called slop. This test needs to run -// long enough that the reported values are distinct, even after accounting for -// this slop. -TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) { - LicenseWithUsageEntry entry; - entry.license_messages().set_api_version(license_api_version_); - entry.MakeAndLoadOnline(this); - Session& s = entry.session(); - - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - - const int64_t kDotIntervalInSeconds = 5; - const int64_t kIdleInSeconds = 20; - const int64_t kPlaybackLoopInSeconds = 2 * 60; - - cout << "This test verifies the elapsed time reported in the usage table " - "for a 2 minute simulated playback." - << endl; - cout << "The total time for this test is about " - << kPlaybackLoopInSeconds + 2 * kIdleInSeconds << " seconds." << endl; - cout << "Wait " << kIdleInSeconds - << " seconds to verify usage table time before playback." << endl; - - PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); - - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); - cout << "Start simulated playback..." << endl; - - int64_t dot_time = kDotIntervalInSeconds; - int64_t playback_time = 0; - const int64_t start_time = wvutil::Clock().GetCurrentTime(); - do { - ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - wvutil::TestSleep::Sleep(kShortSleep); - playback_time = wvutil::Clock().GetCurrentTime() - start_time; - ASSERT_LE(0, playback_time); - if (playback_time >= dot_time) { - cout << "."; - cout.flush(); - dot_time += kDotIntervalInSeconds; - } - } while (playback_time < kPlaybackLoopInSeconds); - cout << "\nSimulated playback time = " << playback_time << " seconds.\n"; - - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - EXPECT_NEAR(s.pst_report().seconds_since_first_decrypt() - - s.pst_report().seconds_since_last_decrypt(), - playback_time, kUsageTableTimeTolerance); - - // We must update the usage entry BEFORE sleeping, not after. - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - - cout << "Wait another " << kIdleInSeconds - << " seconds " - "to verify usage table time since playback ended." - << endl; - PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); - - // At this point, this is what we expect: - // idle playback loop idle - // |-----|-------------------------|-----| - // |<--->| = seconds_since_last_decrypt - // |<----------------------------->| = seconds_since_first_decrypt - // |<------------------------------------| = seconds_since_license_received - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); -} - -// This test class is only used to roll back the wall clock. It is used to -// verify that OEMCrypto's system clock is monotonic. It is should only be run -// on a device that allows an application to set the clock. -class OEMCryptoUsageTableTestWallClock : public OEMCryptoUsageTableTest { - public: - void SetUp() override { OEMCryptoUsageTableTest::SetUp(); } - - void TearDown() override { - wvutil::TestSleep::ResetRollback(); - OEMCryptoUsageTableTest::TearDown(); - } -}; - -// NOTE: This test needs root access since clock_settime messes with the system -// time in order to verify that OEMCrypto protects against rollbacks in usage -// entries. Therefore, this test is filtered if not run as root. -// We don't test roll-forward protection or instances where the user rolls back -// the time to the last decrypt call since this requires hardware-secure clocks -// to guarantee. -// -// This test overlaps two tests in parallel because they each have several -// seconds of sleeping, then we roll the system clock back, and then we sleep -// some more. -// For the first test, we use entry1. The playback duration is 6 short -// intervals. We play for 3, roll the clock back 2, and then play for 3 more. -// We then sleep until after the allowed playback duration and try to play. If -// OEMCrypto allows the rollback, then there is only 5 intervals, which is -// legal. But if OEMCrypto forbids the rollback, then there is 8 intervals of -// playback, which is not legal. -// -// For the second test, we use entry2. The rental duration is 6 short -// intervals. The times are the same as for entry1, except we do not start -// playback for entry2 until the end. - -// clang-format off -// [--][--][--][--][--][--][--] -- playback or rental limit. -// -// Here's what the system clock sees with rollback: -// [--][--][--] 3 short intervals of playback or sleep -// <------> Rollback 2 short intervals. -// [--][--][--] 3 short intervals of playback or sleep -// [--] 1 short intervals of sleep. -// -// Here's what the system clock sees without rollback: -// [--][--][--] 3 short intervals of playback or sleep -// [--][--][--] 3 short intervals of playback or sleep -// [--][--]X 2 short intervals of sleep. -// -// |<---------------------------->| 8 short intervals from license received -// until pst reports generated. -// clang-format on - -TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { - cout << "This test temporarily rolls back the system time in order to verify " - << "that the usage report accounts for the change. After the test, it " - << "rolls the clock back forward." << endl; - constexpr int kRollBackTime = kShortSleep * 2; - constexpr int kPlaybackCount = 3; - constexpr int kTotalTime = kShortSleep * 8; - - LicenseWithUsageEntry entry1; - entry1.license_messages() - .core_response() - .timer_limits.total_playback_duration_seconds = 7 * kShortSleep; - entry1.MakeOfflineAndClose(this); - Session& s1 = entry1.session(); - ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this)); - - LicenseWithUsageEntry entry2; - entry2.license_messages() - .core_response() - .timer_limits.rental_duration_seconds = 7 * kShortSleep; - entry2.MakeOfflineAndClose(this); - Session& s2 = entry2.session(); - ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); - - // Start with three short intervals of playback for entry1. - for (int i = 0; i < kPlaybackCount; i++) { - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - wvutil::TestSleep::Sleep(kShortSleep); - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - } - - cout << "Rolling the system time back..." << endl; - ASSERT_TRUE(wvutil::TestSleep::RollbackSystemTime(kRollBackTime)); - - // Three more short intervals of playback after the rollback. - for (int i = 0; i < kPlaybackCount; i++) { - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - wvutil::TestSleep::Sleep(kShortSleep); - ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - } - - // One short interval of sleep to push us past the 6 interval duration. - wvutil::TestSleep::Sleep(2 * kShortSleep); - - // Should not be able to continue playback in entry1. - ASSERT_NO_FATAL_FAILURE( - entry1.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); - // Should not be able to start playback in entry2. - ASSERT_NO_FATAL_FAILURE( - entry2.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED)); - - // Now we look at the usage reports: - ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); - - ASSERT_NO_FATAL_FAILURE(s1.GenerateReport(entry1.pst())); - wvutil::Unpacked_PST_Report report1 = s1.pst_report(); - EXPECT_EQ(report1.status(), kActive); - EXPECT_GE(report1.seconds_since_license_received(), kTotalTime); - EXPECT_GE(report1.seconds_since_first_decrypt(), kTotalTime); - - ASSERT_NO_FATAL_FAILURE(s2.GenerateReport(entry2.pst())); - wvutil::Unpacked_PST_Report report2 = s2.pst_report(); - EXPECT_EQ(report2.status(), kUnused); - EXPECT_GE(report2.seconds_since_license_received(), kTotalTime); -} - -// Verify that a large PST can be used with usage table entries. -TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) { - std::string pst(kMaxPSTLength, 'a'); // A large PST. - LicenseWithUsageEntry entry(pst); - entry.MakeOfflineAndClose(this); - Session& s = entry.session(); - - ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR()); // Should be able to decrypt. - ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. - // After deactivate, should not be able to decrypt. - ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); - ASSERT_NO_FATAL_FAILURE(s.close()); -} - -// Verify that a usage entry with an invalid session cannot be used. -TEST_P(OEMCryptoUsageTableTest, UsageEntryWithInvalidSession) { - std::string pst("pst"); - LicenseWithUsageEntry entry; - entry.license_messages().set_pst(pst); - - entry.session().open(); - ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); - entry.session().close(); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, - OEMCrypto_DeactivateUsageEntry( - entry.session().session_id(), - reinterpret_cast(pst.c_str()), pst.length())); - - entry.session().open(); - ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); - entry.session().close(); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, - OEMCrypto_MoveEntry(entry.session().session_id(), 0)); -} - -// Verify that a usage entry with an invalid session cannot be used. -TEST_P(OEMCryptoUsageTableTest, ReuseUsageEntryWithInvalidSessionAPI17) { - std::string pst("pst"); - LicenseWithUsageEntry entry; - entry.license_messages().set_pst(pst); - - entry.session().open(); - ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); - entry.session().close(); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, - OEMCrypto_ReuseUsageEntry(entry.session().session_id(), 0)); -} - -INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoUsageTableTest, - Range(kCoreMessagesAPI, kCurrentAPI + 1)); - -// These tests only work when the license has a core message. -INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, - Values(kCurrentAPI)); - -// These tests only work when the license has a core message. -INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, - Values(kCurrentAPI)); - -/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index afaebdc..4e3ab9b 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -10,13 +10,14 @@ // On Android, these features are not optional. This set of unit tests // verify that these features are implemented. // -// In the file oemcrypto_test.cpp, the unit tests only verify correct +// In the other oemcrypto test files, the unit tests only verify correct // functionality for functions that are implemented. Android devices must pass -// unit tests in both files. +// unit tests in this file also. #include -#include "oec_test_data.h" #include "OEMCryptoCENC.h" +#include "oec_device_features.h" +#include "oec_test_data.h" namespace wvoec { @@ -26,6 +27,8 @@ class OEMCryptoAndroidLMPTest : public ::testing::Test { void SetUp() override { OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + OEMCrypto_SetMaxAPIVersion(kCurrentAPI); + OEMCrypto_EnterTestMode(); } void TearDown() override { OEMCrypto_Terminate(); } @@ -69,18 +72,18 @@ TEST_F(OEMCryptoAndroidLMPTest, RewrapDeviceRSAKeyImplemented) { TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) { ASSERT_NE( OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Encrypt(0, nullptr, 0, nullptr, + OEMCrypto_Generic_Encrypt(nullptr, 0, nullptr, 0, nullptr, OEMCrypto_AES_CBC_128_NO_PADDING, nullptr)); ASSERT_NE( OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Decrypt(0, nullptr, 0, nullptr, + OEMCrypto_Generic_Decrypt(nullptr, 0, nullptr, 0, nullptr, OEMCrypto_AES_CBC_128_NO_PADDING, nullptr)); ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Sign(0, nullptr, 0, OEMCrypto_HMAC_SHA256, - nullptr, nullptr)); + OEMCrypto_Generic_Sign(nullptr, 0, nullptr, 0, + OEMCrypto_HMAC_SHA256, nullptr, nullptr)); ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Verify(0, nullptr, 0, OEMCrypto_HMAC_SHA256, - nullptr, 0)); + OEMCrypto_Generic_Verify(nullptr, 0, nullptr, 0, + OEMCrypto_HMAC_SHA256, nullptr, 0)); } // Android requires support of usage table. The usage table is used for Secure @@ -110,9 +113,10 @@ TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) { // If they are not using Provisioning 2.0, then they must use Provisioning 3.0. TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) { if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox( - reinterpret_cast(&kTestKeybox), - sizeof(kTestKeybox))); + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_LoadTestKeybox(reinterpret_cast(&kTestKeybox), + sizeof(kTestKeybox))); } else { // Android should use keybox or provisioning 3.0. ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); diff --git a/oemcrypto/test/oemcrypto_test_main.cpp b/oemcrypto/test/oemcrypto_test_main.cpp index 8a702cf..0779b11 100644 --- a/oemcrypto/test/oemcrypto_test_main.cpp +++ b/oemcrypto/test/oemcrypto_test_main.cpp @@ -46,7 +46,13 @@ int main(int argc, char** argv) { } wvutil::g_cutoff = static_cast(verbosity); wvoec::global_features.Initialize(); - wvoec::global_features.set_cast_receiver(is_cast_receiver); + if (is_cast_receiver) { + // Turn it on if passed in on the command line. Do not turn these tests off + // automtically -- instead, we'll let the caller filter them out if they + // need to. These tests will normally only run if the device claims to + // support being a cast receiver. + wvoec::global_features.set_cast_receiver(is_cast_receiver); + } // Init GTest after device properties has been initialized. ::testing::InitGoogleTest(&argc, argv); // If the user requests --no_filter, we don't change the filter, otherwise, we diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 3fbd0e4..44d0984 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -10,13 +10,20 @@ 'static_libcpp%' : 'false', }, 'sources': [ + 'GEN_api_lock_file.c', 'oec_device_features.cpp', 'oec_decrypt_fallback_chain.cpp', 'oec_key_deriver.cpp', 'oec_session_util.cpp', 'oemcrypto_corpus_generator_helper.cpp', 'oemcrypto_session_tests_helper.cpp', + 'oemcrypto_basic_test.cpp', + 'oemcrypto_decrypt_test.cpp', + 'oemcrypto_license_test.cpp', + 'oemcrypto_provisioning_test.cpp', + 'oemcrypto_usage_table_test.cpp', 'oemcrypto_test.cpp', + '<(jsmn_dir)/jsmn.c', ], 'conditions': [ ['test_opk_serialization_version=="true"', { @@ -39,6 +46,8 @@ '<(oemcrypto_dir)/test/fuzz_tests', '<(oemcrypto_dir)/odk/include', '<(oemcrypto_dir)/util/include', + '<(json_dir)/single_include', + '<(jsmn_dir)', ], 'defines': [ 'OEMCRYPTO_TESTS', @@ -49,6 +58,17 @@ '<(oemcrypto_dir)/test/ota_keybox_test.cpp', ], }], + ['generate_code_coverage_report=="true"', { + # Include flags to generate source based code coverage reports. + 'cflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + 'ldflags': [ + '-fprofile-instr-generate', + '-fcoverage-mapping', + ], + }], ], 'dependencies': [ '<(oemcrypto_dir)/odk/src/odk.gyp:odk', diff --git a/oemcrypto/test/oemcrypto_usage_table_test.cpp b/oemcrypto/test/oemcrypto_usage_table_test.cpp new file mode 100644 index 0000000..8b78b14 --- /dev/null +++ b/oemcrypto/test/oemcrypto_usage_table_test.cpp @@ -0,0 +1,1707 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include "oemcrypto_usage_table_test.h" + +using ::testing::Range; +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) { + // local struct to hold count values from core message + typedef struct counts { + uint32_t prov; + uint32_t lic; + uint32_t decrypt; + uint64_t mgn; + } counts; + + // prep and sign provisioning2 request, then extract counter values + auto provision2 = [&](counts* c) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + c->prov = + provisioning_messages.core_request().counter_info.provisioning_count; + c->lic = provisioning_messages.core_request().counter_info.license_count; + c->decrypt = + provisioning_messages.core_request().counter_info.decrypt_count; + c->mgn = provisioning_messages.core_request() + .counter_info.master_generation_number; + }; + + // prep and sign provisioning4 request, then extract counter values + auto provision4 = [&](counts* c) { + // Same as SessionUtil::CreateProv4OEMKey, but we can't extract counter + // values using that function + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + Provisioning40RoundTrip provisioning_messages(&s); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(true)); + ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey( + provisioning_messages.oem_key_type(), + provisioning_messages.oem_public_key().data(), + provisioning_messages.oem_public_key().size())); + wrapped_oem_key_ = provisioning_messages.wrapped_oem_key(); + oem_public_key_ = provisioning_messages.oem_public_key(); + oem_key_type_ = provisioning_messages.oem_key_type(); + ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest()); + ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadOEMCertResponse()); + c->prov = + provisioning_messages.core_request().counter_info.provisioning_count; + c->lic = provisioning_messages.core_request().counter_info.license_count; + c->decrypt = + provisioning_messages.core_request().counter_info.decrypt_count; + c->mgn = provisioning_messages.core_request() + .counter_info.master_generation_number; + }; + + if (global_features.provisioning_method == OEMCrypto_OEMCertificate || + global_features.provisioning_method == OEMCrypto_DrmCertificate) { + GTEST_SKIP() << "Provisioning method does not increment prov counter"; + } else if (global_features.provisioning_method == OEMCrypto_Keybox) { + counts c1, c2; + provision2(&c1); + provision2(&c2); + + ASSERT_TRUE(c2.prov > c1.prov); + ASSERT_TRUE(c2.lic == c1.lic); + ASSERT_TRUE(c2.decrypt == c1.decrypt); + ASSERT_TRUE(c2.mgn == c1.mgn); + } else if (global_features.provisioning_method == + OEMCrypto_BootCertificateChain) { + counts c1, c2; + provision4(&c1); + provision4(&c2); + + ASSERT_TRUE(c2.prov > c1.prov); + ASSERT_TRUE(c2.lic == c1.lic); + ASSERT_TRUE(c2.decrypt == c1.decrypt); + ASSERT_TRUE(c2.mgn == c1.mgn); + } +} + +// Test that successive calls to PrepAndSignLicenseRequest only increase +// the license count in the ODK message +TEST_F(OEMCryptoSessionTests, License_IncrementCounterAPI18) { + Session s; + s.open(); + LicenseRoundTrip license_messages(&s); + InstallTestDrmKey(&s); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + uint32_t prov_count1 = + license_messages.core_request().counter_info.provisioning_count; + uint32_t lic_count1 = + license_messages.core_request().counter_info.license_count; + uint32_t decrypt_count1 = + license_messages.core_request().counter_info.decrypt_count; + uint64_t master_generation_number1 = + license_messages.core_request().counter_info.master_generation_number; + + Session s2; + s2.open(); + LicenseRoundTrip license_messages2(&s2); + InstallTestDrmKey(&s2); + ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest()); + uint32_t prov_count2 = + license_messages2.core_request().counter_info.provisioning_count; + uint32_t lic_count2 = + license_messages2.core_request().counter_info.license_count; + uint32_t decrypt_count2 = + license_messages2.core_request().counter_info.decrypt_count; + uint64_t master_generation_number2 = + license_messages2.core_request().counter_info.master_generation_number; + + ASSERT_TRUE(prov_count2 == prov_count1); + ASSERT_TRUE(lic_count2 > lic_count1); + ASSERT_TRUE(decrypt_count2 == decrypt_count1); + ASSERT_TRUE(master_generation_number2 == master_generation_number1); +} + +// Test that the license request includes the master generation number, and that +// it is incremented correctly after usage table modification (save offline +// license) and decrypt. Also test that decrypt count increments. +TEST_F(OEMCryptoSessionTests, MasterGeneration_IncrementCounterAPI18) { + if (!OEMCrypto_SupportsUsageTable()) { + GTEST_SKIP() << "Usage table not supported, so master generation number " + "does not need to be checked."; + } + Session s1; + s1.open(); + LicenseRoundTrip license_messages(&s1); + InstallTestDrmKey(&s1); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + uint32_t prov_count1 = + license_messages.core_request().counter_info.provisioning_count; + uint32_t lic_count1 = + license_messages.core_request().counter_info.license_count; + uint32_t decrypt_count1 = + license_messages.core_request().counter_info.decrypt_count; + uint64_t master_generation_number1 = + license_messages.core_request().counter_info.master_generation_number; + + // do the same as ReloadOfflineLicense to push the master generation number + // up + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(kCurrentAPI); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + + Session s2; + s2.open(); + LicenseRoundTrip license_messages2(&s2); + InstallTestDrmKey(&s2); + ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest()); + uint32_t prov_count2 = + license_messages2.core_request().counter_info.provisioning_count; + uint32_t lic_count2 = + license_messages2.core_request().counter_info.license_count; + uint32_t decrypt_count2 = + license_messages2.core_request().counter_info.decrypt_count; + uint64_t master_generation_number2 = + license_messages2.core_request().counter_info.master_generation_number; + + ASSERT_TRUE(prov_count2 == prov_count1); + ASSERT_TRUE(lic_count2 > lic_count1); + ASSERT_TRUE(decrypt_count2 > decrypt_count1); + ASSERT_TRUE(master_generation_number2 > master_generation_number1); +} +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeInvalidUsageEntryNumber) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + Session s; + s.open(); + InstallTestDrmKey(&s); + const uint32_t usage_entry_number = kHugeRandomNumber; + ASSERT_NO_FATAL_FAILURE(OEMCrypto_LoadUsageEntry( + s.session_id(), usage_entry_number, s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); +} + +// Test an online or streaming license with PST. This license requires a +// valid nonce and can only be loaded once. +TEST_P(OEMCryptoUsageTableTest, OnlineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + + // test repeated report generation + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + // Flag the entry as inactive. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // It should report as inactive. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + // Decrypt should fail. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + // We could call DeactivateUsageEntry multiple times. The state should not + // change. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // It should report as inactive. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); +} + +// Test the usage report when the license is loaded but the keys are never +// used for decryption. +TEST_P(OEMCryptoUsageTableTest, OnlineLicenseUnused) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // No decrypt. We do not use this license. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + // Flag the entry as inactive. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // It should report as inactive. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); + // Decrypt should fail. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + // We could call DeactivateUsageEntry multiple times. The state should not + // change. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // It should report as inactive. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); +} + +// Test that the usage table has been updated and saved before a report can be +// generated. +TEST_P(OEMCryptoUsageTableTest, ForbidReportWithNoUpdate) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + // Cannot generate a report without first updating the file. + ASSERT_NO_FATAL_FAILURE( + s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // Now it's OK. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + // Flag the entry as inactive. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + // Cannot generate a report without first updating the file. + ASSERT_NO_FATAL_FAILURE( + s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE)); + // Decrypt should fail. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// Test an online license with a license renewal. +TEST_P(OEMCryptoUsageTableTest, OnlineLicenseWithRefreshAPI16) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + + RenewalRoundTrip renewal_messages(&entry.license_messages()); + MakeRenewalRequest(&renewal_messages); + LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); +} + +// Verify that a streaming license cannot be reloaded. +TEST_P(OEMCryptoUsageTableTest, RepeatOnlineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s.close()); + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s2)); + s2.LoadUsageEntry(s); // Use the same entry. + ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s2)); +} + +// An offline license should not load on the first call if the nonce is bad. +TEST_P(OEMCryptoUsageTableTest, OnlineBadNonce) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + license_messages.set_control(wvoec::kControlNonceEnabled | + wvoec::kControlNonceRequired); + license_messages.set_pst("my-pst"); + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + for (uint32_t i = 0; i < license_messages.num_keys(); i++) + license_messages.response_data().keys[i].control.nonce ^= 42; + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); +} + +// A license with non-zero replay control bits needs a valid pst. +TEST_P(OEMCryptoUsageTableTest, OnlineEmptyPST) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + license_messages.set_control(wvoec::kControlNonceEnabled | + wvoec::kControlNonceRequired); + // DO NOT SET PST: license_messages.set_pst(pst); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); +} + +// A license with non-zero replay control bits needs a valid pst. +TEST_P(OEMCryptoUsageTableTest, OnlineMissingEntry) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + license_messages.set_control(wvoec::kControlNonceEnabled | + wvoec::kControlNonceRequired); + license_messages.set_pst("my-pst"); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + // ENTRY NOT CREATED: ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); +} + +// Sessions should have at most one entry at a time. This tests different +// orderings of CreateNewUsageEntry and LoadUsageEntry calls. +TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { + // Entry Count: we start each test with an empty header. + uint32_t usage_entry_number; + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + Session& s = entry.session(); + // Make first entry 0. + ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); + + // Load an entry, then try to create a second. + ASSERT_NO_FATAL_FAILURE(s.open()); + // Reload entry 0. + ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); + // Create new entry 1 should fail. + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_CreateNewUsageEntry(entry.session().session_id(), + &usage_entry_number)); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Create an entry, then try to load a second. + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + // Create entry 1. + ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); + // Try to reload entry 0. + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageEntry(s2.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + ASSERT_NO_FATAL_FAILURE(s2.close()); + + // Reload an entry and a license, then try to load the same entry again. + // This reloads entry 0. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Create an entry, then try to create a second entry. + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry( + s2.session_id(), &usage_entry_number)); +} + +// An entry can be loaded in only one session at a time. +TEST_P(OEMCryptoUsageTableTest, LoadEntryInMultipleSessions) { + // Entry Count: we start each test with an empty header. + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + Session& s = entry.session(); + // Make first entry 0. + ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); + const uint32_t usage_entry_number = s.usage_entry_number(); + EXPECT_EQ(usage_entry_number, 0u); // Should be only entry in this test. + + // Load an entry, then try to create a second. + ASSERT_NO_FATAL_FAILURE(s.open()); + // Reload entry 0. + ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); + + // Create an entry, then try to load a second. + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + // Try to load entry 0 into session 2. + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); +} + +// Test generic encrypt when the license uses a PST. +TEST_P(OEMCryptoUsageTableTest, GenericCryptoEncrypt) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.set_generic_crypto(true); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + OEMCryptoResult sts; + unsigned int key_index = 0; + vector expected_encrypted; + EncryptBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, + &expected_encrypted); + vector key_handle; + sts = + GetKeyHandleIntoVector(s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector encrypted(clear_buffer_.size()); + sts = OEMCrypto_Generic_Encrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + encrypted.data()); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(expected_encrypted, encrypted); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + encrypted.assign(clear_buffer_.size(), 0); + sts = OEMCrypto_Generic_Encrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + encrypted.data()); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(encrypted, expected_encrypted); +} + +// Test generic decrypt when the license uses a PST. +TEST_P(OEMCryptoUsageTableTest, GenericCryptoDecrypt) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.set_generic_crypto(true); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + OEMCryptoResult sts; + unsigned int key_index = 1; + vector encrypted; + EncryptBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, + &encrypted); + vector key_handle; + sts = + GetKeyHandleIntoVector(s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector resultant(encrypted.size()); + sts = OEMCrypto_Generic_Decrypt( + key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(clear_buffer_, resultant); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + resultant.assign(encrypted.size(), 0); + sts = OEMCrypto_Generic_Decrypt( + key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(clear_buffer_, resultant); +} + +// Test generic sign when the license uses a PST. +TEST_P(OEMCryptoUsageTableTest, GenericCryptoSign) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.set_generic_crypto(true); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + OEMCryptoResult sts; + unsigned int key_index = 2; + vector expected_signature; + SignBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, + &expected_signature); + + vector key_handle; + sts = + GetKeyHandleIntoVector(s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + size_t gen_signature_length = 0; + sts = OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, nullptr, + &gen_signature_length); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); + vector signature(SHA256_DIGEST_LENGTH); + sts = OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(expected_signature, signature); + + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + signature.assign(SHA256_DIGEST_LENGTH, 0); + gen_signature_length = SHA256_DIGEST_LENGTH; + sts = OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length); + ASSERT_NE(OEMCrypto_SUCCESS, sts); + ASSERT_NE(signature, expected_signature); +} + +// Test generic verify when the license uses a PST. +TEST_P(OEMCryptoUsageTableTest, GenericCryptoVerify) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.set_generic_crypto(true); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + OEMCryptoResult sts; + unsigned int key_index = 3; + vector signature; + SignBufferWithKey(s.license().keys[key_index].key_data, clear_buffer_, + &signature); + + vector key_handle; + sts = + GetKeyHandleIntoVector(s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + sts = OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + sts = OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + +// Test that an offline license can be loaded. +TEST_P(OEMCryptoUsageTableTest, OfflineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); +} + +// Test that an offline license can be loaded and that the license can be +// renewed. +TEST_P(OEMCryptoUsageTableTest, OfflineLicenseRefresh) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoad(this, wvoec::kControlNonceOrEntry); + Session& s = entry.session(); + + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + // License renewal message is signed by client and verified by the server. + RenewalRoundTrip renewal_messages(&entry.license_messages()); + MakeRenewalRequest(&renewal_messages); + LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); +} + +// Test that an offline license can be reloaded in a new session. +TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); +} + +// Test that an offline license can be reloaded in a new session, and then +// refreshed. +TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithRefresh) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + RenewalRoundTrip renewal_messages(&entry.license_messages()); + MakeRenewalRequest(&renewal_messages); + LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); +} + +// Verify that we can still reload an offline license after +// OEMCrypto_Terminate and Initialize are called. This is as close to a reboot +// as we can do in a unit test. +TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithTerminate) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + ShutDown(); // This calls OEMCrypto_Terminate. + Restart(); // This calls OEMCrypto_Initialize. + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); + + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); +} + +// If we attempt to load a second license with the same usage entry as the +// first, but it has different mac keys, then the attempt should fail. This +// is how we verify that we are reloading the same license. +TEST_P(OEMCryptoUsageTableTest, BadReloadOfflineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + + // Offline license with new mac keys should fail. + Session s2; + LicenseRoundTrip license_messages2(&s2); + // Copy the response, and then change the mac keys. + license_messages2.response_data() = entry.license_messages().response_data(); + license_messages2.core_response() = entry.license_messages().core_response(); + license_messages2.response_data().mac_keys[7] ^= 42; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s2)); + // This is a valid license: it is correctly signed. + license_messages2.EncryptAndSignResponse(); + // Load the usage entry should be OK. + ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages2.LoadResponse()); + ASSERT_NO_FATAL_FAILURE(s2.close()); + + // Now we go back to the original license response. It should load OK. + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); +} + +// An offline license should not load on the first call if the nonce is bad. +TEST_P(OEMCryptoUsageTableTest, OfflineBadNonce) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + license_messages.set_control(wvoec::kControlNonceOrEntry); + license_messages.set_pst("my-pst"); + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + for (size_t i = 0; i < license_messages.num_keys(); i++) + license_messages.response_data().keys[i].control.nonce ^= 42; + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); +} + +// An offline license needs a valid pst. +TEST_P(OEMCryptoUsageTableTest, OfflineEmptyPST) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + license_messages.set_control(wvoec::kControlNonceOrEntry); + // DO NOT SET PST: license_messages.set_pst(pst); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry()); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages.LoadResponse()); +} + +// If we try to reload a license with a different PST, the attempt should +// fail. +TEST_P(OEMCryptoUsageTableTest, ReloadOfflineWrongPST) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + + Session s2; + LicenseRoundTrip license_messages2(&s2); + license_messages2.response_data() = entry.license_messages().response_data(); + license_messages2.core_response() = entry.license_messages().core_response(); + // Change the middle of the pst. + license_messages2.response_data().pst[3] ^= 'Z'; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s2)); + // This is a valid license: it is correctly signed. + license_messages2.EncryptAndSignResponse(); + // Load the usage entry should be OK. + ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s)); + ASSERT_NE(OEMCrypto_SUCCESS, license_messages2.LoadResponse()); +} + +// Once a license has been deactivated, the keys can no longer be used for +// decryption. However, we can still generate a usage report. +TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicense) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + // Reload the offline license. + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR()); // Should be able to decrypt. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. + // After deactivate, should not be able to decrypt. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Offline license can not be reused if it has been deactivated. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); + s.close(); + + // But we can still generate a report. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // Sending a release from an offline license that has been deactivate will + // only work if the license server can handle v16 licenses. This is a rare + // condition, so it is OK to break it during the transition months. + entry.license_messages().set_api_version(global_features.api_version); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + // We could call DeactivateUsageEntry multiple times. The state should not + // change. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); +} + +// The usage report should indicate that the keys were never used for +// decryption. +TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicenseUnused) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + // No Decrypt. This license is unused. + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. + // After deactivate, should not be able to decrypt. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Offline license can not be reused if it has been deactivated. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); + s.close(); + + // But we can still generate a report. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // Sending a release from an offline license that has been deactivate will + // only work if the license server can handle v16 licenses. This is a rare + // condition, so it is OK to break it during the transition months. + entry.license_messages().set_api_version(global_features.api_version); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); + // We could call DeactivateUsageEntry multiple times. The state should not + // change. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); +} + +TEST_P(OEMCryptoUsageTableTest, SecureStop) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s.close()); + // When we generate a secure stop without loading the license first, it + // should assume the server does not support core messages. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(entry.ReloadUsageEntry()); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + // It should report as inactive. + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); +} + +// Test update usage table fails when passed a null pointer. +TEST_P(OEMCryptoUsageTableTest, UpdateFailsWithNullPtr) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + size_t header_buffer_length = encrypted_usage_header_.size(); + size_t entry_buffer_length = s.encrypted_usage_entry().size(); + vector buffer(entry_buffer_length); + // Now try to pass in null pointers for the buffers. This should fail. + ASSERT_NE( + OEMCrypto_SUCCESS, + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + buffer.data(), &entry_buffer_length)); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_UpdateUsageEntry( + s.session_id(), encrypted_usage_header_.data(), + &header_buffer_length, nullptr, &entry_buffer_length)); +} + +// Class used to test usage table defragmentation. +class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest { + protected: + void ReloadLicense(LicenseWithUsageEntry* entry) { + Session& s = entry->session(); + ASSERT_NO_FATAL_FAILURE(entry->OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry->TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry->GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(s.close()); + } + + void FailReloadLicense(LicenseWithUsageEntry* entry, + OEMCryptoResult expected_result) { + Session& s = entry->session(); + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_EQ(expected_result, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + + ASSERT_NE(OEMCrypto_SUCCESS, entry->license_messages().LoadResponse()); + ASSERT_NO_FATAL_FAILURE(s.close()); + } + + void ShrinkHeader(uint32_t new_size, + OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { + // We call OEMCrypto_ShrinkUsageTableHeader once with a zero length + // buffer, so that OEMCrypto can tell us how big the buffer should be. + size_t header_buffer_length = 0; + OEMCryptoResult sts = OEMCrypto_ShrinkUsageTableHeader( + new_size, nullptr, &header_buffer_length); + // If we are expecting success, then the first call shall return + // SHORT_BUFFER. However, if we are not expecting success, this first call + // may return either SHORT_BUFFER or the expect error. + if (expected_result == OEMCrypto_SUCCESS) { + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + } else if (sts != OEMCrypto_ERROR_SHORT_BUFFER) { + // If we got any thing from the first call, it should be the expected + // error, and we don't need to call a second time. + ASSERT_EQ(expected_result, sts); + return; + } + // If the first call resulted in SHORT_BUFFER, we should resize the buffer + // and try again. + ASSERT_LT(0u, header_buffer_length); + encrypted_usage_header_.resize(header_buffer_length); + sts = OEMCrypto_ShrinkUsageTableHeader( + new_size, encrypted_usage_header_.data(), &header_buffer_length); + // For the second call, we always demand the expected result. + ASSERT_EQ(expected_result, sts); + if (sts == OEMCrypto_SUCCESS) { + encrypted_usage_header_.resize(header_buffer_length); + } + } +}; + +// Verify that usage table entries can be moved around in the table. +TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { + const size_t ENTRY_COUNT = 10; + vector entries(ENTRY_COUNT); + for (size_t i = 0; i < ENTRY_COUNT; i++) { + entries[i].set_pst("pst " + std::to_string(i)); + ASSERT_NO_FATAL_FAILURE(entries[i].MakeOfflineAndClose(this)) + << "On license " << i << " pst=" << entries[i].pst(); + wvutil::TestSleep::SyncFakeClock(); + } + for (size_t i = 0; i < ENTRY_COUNT; i++) { + ASSERT_NO_FATAL_FAILURE(entries[i].OpenAndReload(this)) + << "On license " << i << " pst=" << entries[i].pst(); + ASSERT_NO_FATAL_FAILURE(entries[i].session().close()) + << "On license " << i << " pst=" << entries[i].pst(); + } + // Move 4 to 1. + ASSERT_NO_FATAL_FAILURE( + entries[4].session().MoveUsageEntry(1, &encrypted_usage_header_)); + // Shrink header to 3 entries 0, 1 was 4, 2. + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(3)); + ShutDown(); + Restart(); + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); + wvutil::TestSleep::SyncFakeClock(); + ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0])); + // Now has index 1. + ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[4])); + ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[2])); + // When 4 was moved to 1, it increased the gen. number in the header. + ASSERT_NO_FATAL_FAILURE( + FailReloadLicense(&entries[1], OEMCrypto_ERROR_GENERATION_SKEW)); + // Index 3 is beyond the end of the table. + ASSERT_NO_FATAL_FAILURE( + FailReloadLicense(&entries[3], OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// A usage table entry cannot be moved into an entry where an open session is +// currently using the entry. +TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToOpenSession) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); + // s0 currently open on index 0. Expect this to fail: + ASSERT_NO_FATAL_FAILURE(entry1.session().MoveUsageEntry( + 0, &encrypted_usage_header_, OEMCrypto_ERROR_ENTRY_IN_USE)); +} + +TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToInvalidHugeEntryIndex) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + entry0.session().open(); + entry0.ReloadUsageEntry(); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_MoveEntry(entry0.session().session_id(), kHugeRandomNumber)); +} + +// The usage table cannot be shrunk if any session is using an entry that +// would be deleted. +TEST_P(OEMCryptoUsageTableDefragTest, ShrinkOverOpenSessions) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); + entry1.session().open(); + ASSERT_NO_FATAL_FAILURE(entry1.ReloadUsageEntry()); + // Since s0 and s1 are open, we can't shrink. + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(1, OEMCrypto_ERROR_ENTRY_IN_USE)); + entry1.session().close(); // Can shrink after closing s1, even if s0 is open. + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(1, OEMCrypto_SUCCESS)); +} + +// Verify the usage table size can be increased. +TEST_P(OEMCryptoUsageTableDefragTest, EnlargeHeader) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + + // Can only shrink the header -- not make it bigger. + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(4, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// A new header can only be created while no entries are in use. +TEST_P(OEMCryptoUsageTableDefragTest, CreateNewHeaderWhileUsingOldOne) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.ReloadUsageEntry()); + const bool kExpectFailure = false; + ASSERT_NO_FATAL_FAILURE(CreateUsageTableHeader(kExpectFailure)); +} + +// Verify that a usage table entry can only be loaded into the correct index +// of the table. +TEST_P(OEMCryptoUsageTableDefragTest, ReloadUsageEntryWrongIndex) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + + entry0.session().set_usage_entry_number(1); + ASSERT_NO_FATAL_FAILURE( + FailReloadLicense(&entry0, OEMCrypto_ERROR_INVALID_SESSION)); +} + +// Verify that a usage table entry cannot be loaded if it has been altered. +TEST_P(OEMCryptoUsageTableDefragTest, ReloadUsageEntryBadData) { + LicenseWithUsageEntry entry; + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + vector data = s.encrypted_usage_entry(); + ASSERT_LT(0UL, data.size()); + data[0] ^= 42; + // Error could be signature or verification error. + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + data.data(), data.size())); +} + +// This verifies we can actually create the required number of usage table +// entries. +TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { + // OEMCrypto is required to store at least 300 entries in the usage table + // header, but it is allowed to store more. This test verifies that if we + // keep adding entries, the error indicates a resource limit. It then + // verifies that all of the successful entries are still valid after we + // throw out the last invalid entry. + + // After API 16, we require 300 entries in the usage table. Before API 16, + // we required 200. + const size_t required_capacity = RequiredUsageSize(); + + // We try to make a much large header, and assume there is an error at some + // point. + const size_t attempt_count = required_capacity * 5; + // Count of how many entries we successfully create. + size_t successful_count = 0; + + // These entries have licenses tied to them. + std::vector> entries; + // Store the status of the last attempt to create an entry. + OEMCryptoResult status = OEMCrypto_SUCCESS; + while (successful_count < attempt_count && status == OEMCrypto_SUCCESS) { + wvutil::TestSleep::SyncFakeClock(); + LOGD("Creating license for entry %zu", successful_count); + entries.push_back( + std::unique_ptr(new LicenseWithUsageEntry())); + entries.back()->set_pst("pst " + std::to_string(successful_count)); + ASSERT_NO_FATAL_FAILURE(entries.back()->MakeOfflineAndClose(this, &status)) + << "Failed creating license for entry " << successful_count; + if (status != OEMCrypto_SUCCESS) { + // Remove the failed session. + entries.resize(entries.size() - 1); + break; + } + EXPECT_EQ(entries.back()->session().usage_entry_number(), successful_count); + successful_count++; + // We don't create a license for each entry. For every license, we'll + // create 10 empty entries. + constexpr size_t filler_count = 10; + for (size_t i = 0; i < filler_count; i++) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry(&status)) + << "Failed creating entry " << successful_count; + if (status != OEMCrypto_SUCCESS) break; + EXPECT_EQ(s.usage_entry_number(), successful_count); + successful_count++; + } + } + LOGD("successful_count = %zu", successful_count); + if (status != OEMCrypto_SUCCESS) { + // If we failed to create this many entries because of limited resources, + // then the error returned should be insufficient resources. + EXPECT_EQ(OEMCrypto_ERROR_INSUFFICIENT_RESOURCES, status) + << "Failed to create license " << successful_count + << ", with wrong error code."; + } + EXPECT_GE(successful_count, required_capacity); + wvutil::TestSleep::SyncFakeClock(); + // Shrink the table a little. + constexpr size_t small_number = 5; + size_t smaller_size = successful_count - small_number; + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(static_cast(smaller_size))); + // Throw out the last license if it was in the part of the table that was + // shrunk. + if (entries.back()->session().usage_entry_number() >= smaller_size) { + entries.pop_back(); + } + // Create a few more license + for (size_t i = 0; i < small_number; i++) { + wvutil::TestSleep::SyncFakeClock(); + entries.push_back( + std::unique_ptr(new LicenseWithUsageEntry())); + entries.back()->set_pst("new pst " + std::to_string(smaller_size + i)); + entries.back()->MakeOfflineAndClose(this); + } + // Make sure that all of the licenses can be reloaded. + for (size_t i = 0; i < entries.size(); i++) { + wvutil::TestSleep::SyncFakeClock(); + Session& s = entries[i]->session(); + ASSERT_NO_FATAL_FAILURE(entries[i]->OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(entries[i]->TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(s.close()); + } +} + +// Verify that usage entries can be created in the position of existing entry +// indexes. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry0.session().close(); + entry1.session().open(); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); +} + +// Verify that usage entries cannot replace an entry that is currently in +// use by a session. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryIndexInUseAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry1.session().open(); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); +} + +// Verify that usage entries cannot be created if the usage entry index is +// too large. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryWithInvalidIndexAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry0.session().close(); + entry1.session().open(); + ASSERT_EQ( + OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number + 42)); +} + +// Verify that usage entries cannot be created if the session already has an +// entry. +TEST_P(OEMCryptoUsageTableDefragTest, + ReuseUsageEntrySessionAlreadyHasEntryAPI17) { + LicenseWithUsageEntry entry; + entry.set_pst("pst 0"); + + // Create 5 entries in the table. + for (int i = 0; i < 5; i++) { + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + entry.session().close(); + } + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + const uint32_t number = entry.session().usage_entry_number(); + ASSERT_EQ( + OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + OEMCrypto_ReuseUsageEntry(entry.session().session_id(), number - 3)); +} + +// This verifies that the usage table header can be loaded if the generation +// number is off by one, but not off by two. +TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { + // This also tests a few other error conditions with usage table headers. + LicenseWithUsageEntry entry; + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + + // Reload the license, and save the header. + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + vector old_usage_header_2_ = encrypted_usage_header_; + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + vector old_usage_header_1_ = encrypted_usage_header_; + vector old_usage_entry_1 = s.encrypted_usage_entry(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s.close()); + + ShutDown(); + Restart(); + // Null pointer generates error. + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageTableHeader( + nullptr, old_usage_header_2_.size())); + ASSERT_NO_FATAL_FAILURE(s.open()); + // Cannot load an entry if header didn't load. + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Modified header generates error. + vector bad_header = encrypted_usage_header_; + bad_header[3] ^= 42; + ASSERT_NE(OEMCrypto_SUCCESS, LoadUsageTableHeader(bad_header)); + ASSERT_NO_FATAL_FAILURE(s.open()); + // Cannot load an entry if header didn't load. + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Old by 2 generation numbers is error. + ASSERT_EQ(OEMCrypto_ERROR_GENERATION_SKEW, + LoadUsageTableHeader(old_usage_header_2_)); + ASSERT_NO_FATAL_FAILURE(s.open()); + // Cannot load an entry if header didn't load. + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); + ASSERT_NO_FATAL_FAILURE(s.close()); + + // Old by 1 generation numbers is just warning. + ASSERT_EQ(OEMCrypto_WARNING_GENERATION_SKEW, + LoadUsageTableHeader(old_usage_header_1_)); + // Everything else should still work. The old entry goes with the old + // header. + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), + old_usage_entry_1.data(), + old_usage_entry_1.size())); + ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s)); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey()); + ASSERT_EQ(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse()); +} + +TEST_P(OEMCryptoUsageTableTest, LoadAndReloadEntries) { + constexpr size_t kEntryCount = 10; + std::vector entries(kEntryCount); + + for (LicenseWithUsageEntry& entry : entries) { + entry.license_messages().set_api_version(license_api_version_); + } + + for (size_t i = 0; i < kEntryCount; ++i) { + const std::string create_description = + "Creating entry #" + std::to_string(i); + // Create and update a new entry. + LicenseWithUsageEntry& new_entry = entries[i]; + ASSERT_NO_FATAL_FAILURE(new_entry.MakeOfflineAndClose(this)) + << create_description; + // Reload all entries, starting with the most recently created. + for (size_t j = 0; j <= i; ++j) { + const std::string reload_description = + "Reloading entry #" + std::to_string(i - j) + + ", after creating entry #" + std::to_string(i); + LicenseWithUsageEntry& old_entry = entries[i - j]; + ASSERT_NO_FATAL_FAILURE(old_entry.session().open()); + ASSERT_NO_FATAL_FAILURE(old_entry.ReloadUsageEntry()) + << reload_description; + ASSERT_NO_FATAL_FAILURE( + old_entry.session().UpdateUsageEntry(&encrypted_usage_header_)) + << reload_description; + ASSERT_NO_FATAL_FAILURE(old_entry.session().close()); + } + } +} + +// A usage report with the wrong pst should fail. +TEST_P(OEMCryptoUsageTableTest, GenerateReportWrongPST) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE( + s.GenerateReport("wrong_pst", OEMCrypto_ERROR_WRONG_PST)); +} + +// Test usage table timing. +TEST_P(OEMCryptoUsageTableTest, TimingTest) { + LicenseWithUsageEntry entry1; + entry1.license_messages().set_api_version(license_api_version_); + Session& s1 = entry1.session(); + entry1.set_pst("my_pst_1"); + ASSERT_NO_FATAL_FAILURE(entry1.MakeOfflineAndClose(this)); + + LicenseWithUsageEntry entry2; + entry2.license_messages().set_api_version(license_api_version_); + Session& s2 = entry2.session(); + entry2.set_pst("my_pst_2"); + ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this)); + + LicenseWithUsageEntry entry3; + entry3.license_messages().set_api_version(license_api_version_); + Session& s3 = entry3.session(); + entry3.set_pst("my_pst_3"); + ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this)); + + ASSERT_NO_FATAL_FAILURE(entry1.MakeOfflineAndClose(this)); + ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this)); + ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this)); + + wvutil::TestSleep::Sleep(kLongSleep); + ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + + ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); + + wvutil::TestSleep::Sleep(kLongSleep); + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); + + wvutil::TestSleep::Sleep(kLongSleep); + ASSERT_NO_FATAL_FAILURE(entry1.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s1.close()); + ASSERT_NO_FATAL_FAILURE(s2.close()); + + wvutil::TestSleep::Sleep(kLongSleep); + // This is as close to reboot as we can simulate in code. + ShutDown(); + wvutil::TestSleep::Sleep(kShortSleep); + Restart(); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), + encrypted_usage_header_.size())); + + // After a reboot, we should be able to reload keys, and generate reports. + wvutil::TestSleep::Sleep(kLongSleep); + ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s2.close()); + + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(entry1.ReloadUsageEntry()); + ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(entry3.OpenAndReload(this)); + + wvutil::TestSleep::Sleep(kLongSleep); + ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry1.GenerateVerifyReport(kInactiveUsed)); + ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry2.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(s3.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry3.GenerateVerifyReport(kUnused)); +} + +// Verify the times in the usage report. For performance reasons, we allow +// the times in the usage report to be off by as much as kUsageTimeTolerance, +// which is 10 seconds. This acceptable error is called slop. This test needs +// to run long enough that the reported values are distinct, even after +// accounting for this slop. +TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + + const int64_t kDotIntervalInSeconds = 5; + const int64_t kIdleInSeconds = 20; + const int64_t kPlaybackLoopInSeconds = 2 * 60; + + cout << "This test verifies the elapsed time reported in the usage table " + "for a 2 minute simulated playback." + << endl; + cout << "The total time for this test is about " + << kPlaybackLoopInSeconds + 2 * kIdleInSeconds << " seconds." << endl; + cout << "Wait " << kIdleInSeconds + << " seconds to verify usage table time before playback." << endl; + + PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); + + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused)); + cout << "Start simulated playback..." << endl; + + int64_t dot_time = kDotIntervalInSeconds; + int64_t playback_time = 0; + const int64_t start_time = wvutil::Clock().GetCurrentTime(); + do { + ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + wvutil::TestSleep::Sleep(kShortSleep); + playback_time = wvutil::Clock().GetCurrentTime() - start_time; + ASSERT_LE(0, playback_time); + if (playback_time >= dot_time) { + cout << "."; + cout.flush(); + dot_time += kDotIntervalInSeconds; + } + } while (playback_time < kPlaybackLoopInSeconds); + cout << "\nSimulated playback time = " << playback_time << " seconds.\n"; + + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + EXPECT_NEAR(s.pst_report().seconds_since_first_decrypt() - + s.pst_report().seconds_since_last_decrypt(), + playback_time, kUsageTableTimeTolerance); + + // We must update the usage entry BEFORE sleeping, not after. + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + + cout << "Wait another " << kIdleInSeconds + << " seconds " + "to verify usage table time since playback ended." + << endl; + PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds); + + // At this point, this is what we expect: + // idle playback loop idle + // |-----|-------------------------|-----| + // |<--->| = seconds_since_last_decrypt + // |<----------------------------->| = seconds_since_first_decrypt + // |<------------------------------------| = seconds_since_license_received + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + +// This test class is only used to roll back the wall clock. It is used to +// verify that OEMCrypto's system clock is monotonic. It is should only be +// run on a device that allows an application to set the clock. +class OEMCryptoUsageTableTestWallClock : public OEMCryptoUsageTableTest { + public: + void SetUp() override { OEMCryptoUsageTableTest::SetUp(); } + + void TearDown() override { + wvutil::TestSleep::ResetRollback(); + OEMCryptoUsageTableTest::TearDown(); + } +}; + +// NOTE: This test needs root access since clock_settime messes with the +// system time in order to verify that OEMCrypto protects against rollbacks in +// usage entries. Therefore, this test is filtered if not run as root. We +// don't test roll-forward protection or instances where the user rolls back +// the time to the last decrypt call since this requires hardware-secure +// clocks to guarantee. +// +// This test overlaps two tests in parallel because they each have several +// seconds of sleeping, then we roll the system clock back, and then we sleep +// some more. +// For the first test, we use entry1. The playback duration is 6 short +// intervals. We play for 3, roll the clock back 2, and then play for 3 more. +// We then sleep until after the allowed playback duration and try to play. If +// OEMCrypto allows the rollback, then there is only 5 intervals, which is +// legal. But if OEMCrypto forbids the rollback, then there is 8 intervals of +// playback, which is not legal. +// +// For the second test, we use entry2. The rental duration is 6 short +// intervals. The times are the same as for entry1, except we do not start +// playback for entry2 until the end. + +// clang-format off +// [--][--][--][--][--][--][--] -- playback or rental limit. +// +// Here's what the system clock sees with rollback: +// [--][--][--] 3 short intervals of playback or sleep +// <------> Rollback 2 short intervals. +// [--][--][--] 3 short intervals of playback or sleep +// [--] 1 short intervals of sleep. +// +// Here's what the system clock sees without rollback: +// [--][--][--] 3 short intervals of playback or sleep +// [--][--][--] 3 short intervals of playback or sleep +// [--][--]X 2 short intervals of sleep. +// +// |<---------------------------->| 8 short intervals from license received +// until pst reports generated. +// clang-format on + +TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { + cout << "This test temporarily rolls back the system time in order to " + "verify " + << "that the usage report accounts for the change. After the test, it " + << "rolls the clock back forward." << endl; + constexpr int kRollBackTime = kShortSleep * 2; + constexpr int kPlaybackCount = 3; + constexpr int kTotalTime = kShortSleep * 8; + + LicenseWithUsageEntry entry1; + entry1.license_messages() + .core_response() + .timer_limits.total_playback_duration_seconds = 7 * kShortSleep; + entry1.MakeOfflineAndClose(this); + Session& s1 = entry1.session(); + ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this)); + + LicenseWithUsageEntry entry2; + entry2.license_messages() + .core_response() + .timer_limits.rental_duration_seconds = 7 * kShortSleep; + entry2.MakeOfflineAndClose(this); + Session& s2 = entry2.session(); + ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); + + // Start with three short intervals of playback for entry1. + for (int i = 0; i < kPlaybackCount; i++) { + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + wvutil::TestSleep::Sleep(kShortSleep); + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + } + + cout << "Rolling the system time back..." << endl; + ASSERT_TRUE(wvutil::TestSleep::RollbackSystemTime(kRollBackTime)); + + // Three more short intervals of playback after the rollback. + for (int i = 0; i < kPlaybackCount; i++) { + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + wvutil::TestSleep::Sleep(kShortSleep); + ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); + } + + // One short interval of sleep to push us past the 6 interval duration. + wvutil::TestSleep::Sleep(2 * kShortSleep); + + // Should not be able to continue playback in entry1. + ASSERT_NO_FATAL_FAILURE( + entry1.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); + // Should not be able to start playback in entry2. + ASSERT_NO_FATAL_FAILURE( + entry2.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED)); + + // Now we look at the usage reports: + ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); + + ASSERT_NO_FATAL_FAILURE(s1.GenerateReport(entry1.pst())); + wvutil::Unpacked_PST_Report report1 = s1.pst_report(); + EXPECT_EQ(report1.status(), kActive); + EXPECT_GE(report1.seconds_since_license_received(), kTotalTime); + EXPECT_GE(report1.seconds_since_first_decrypt(), kTotalTime); + + ASSERT_NO_FATAL_FAILURE(s2.GenerateReport(entry2.pst())); + wvutil::Unpacked_PST_Report report2 = s2.pst_report(); + EXPECT_EQ(report2.status(), kUnused); + EXPECT_GE(report2.seconds_since_license_received(), kTotalTime); +} + +// Verify that a large PST can be used with usage table entries. +TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) { + std::string pst(kMaxPSTLength, 'a'); // A large PST. + LicenseWithUsageEntry entry(pst); + entry.MakeOfflineAndClose(this); + Session& s = entry.session(); + + ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR()); // Should be able to decrypt. + ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. + // After deactivate, should not be able to decrypt. + ASSERT_NO_FATAL_FAILURE( + entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); + ASSERT_NO_FATAL_FAILURE(s.close()); +} + +// Verify that a usage entry with an invalid session cannot be used. +TEST_P(OEMCryptoUsageTableTest, UsageEntryWithInvalidSession) { + std::string pst("pst"); + LicenseWithUsageEntry entry; + entry.license_messages().set_pst(pst); + + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + entry.session().close(); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_DeactivateUsageEntry( + entry.session().session_id(), + reinterpret_cast(pst.c_str()), pst.length())); + + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + entry.session().close(); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_MoveEntry(entry.session().session_id(), 0)); +} + +// Verify that a usage entry with an invalid session cannot be used. +TEST_P(OEMCryptoUsageTableTest, ReuseUsageEntryWithInvalidSessionAPI17) { + std::string pst("pst"); + LicenseWithUsageEntry entry; + entry.license_messages().set_pst(pst); + + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + entry.session().close(); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_ReuseUsageEntry(entry.session().session_id(), 0)); +} + +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoUsageTableTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); + +// These tests only work when the license has a core message. +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, + Values(kCurrentAPI)); + +// These tests only work when the license has a core message. +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, + Values(kCurrentAPI)); + +/// @} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/oemcrypto_usage_table_test.h b/oemcrypto/test/oemcrypto_usage_table_test.h new file mode 100644 index 0000000..9ffd3fc --- /dev/null +++ b/oemcrypto/test/oemcrypto_usage_table_test.h @@ -0,0 +1,379 @@ +// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEMCRYPTO_USAGE_TABLE_TEST_ +#define CDM_OEMCRYPTO_USAGE_TABLE_TEST_ + +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_license_test.h" +#include "test_sleep.h" + +namespace wvoec { + +class OEMCryptoRefreshTest : public OEMCryptoLicenseTest { + protected: + void SetUp() override { + OEMCryptoLicenseTest::SetUp(); + // These values allow us to run a few simple duration tests or just start + // playback right away. All times are in seconds since the license was + // signed. + // Soft expiry false means timers are strictly enforce. + timer_limits_.soft_enforce_rental_duration = true; + timer_limits_.soft_enforce_playback_duration = false; + // Playback may begin immediately. + timer_limits_.earliest_playback_start_seconds = 0; + // First playback may be within the first two seconds. + timer_limits_.rental_duration_seconds = kDuration; + // Once started, playback may last two seconds without a renewal. + timer_limits_.initial_renewal_duration_seconds = kDuration; + // Total playback is not limited. + timer_limits_.total_playback_duration_seconds = 0; + } + + void LoadLicense() { + license_messages_.core_response().timer_limits = timer_limits_; + 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 MakeRenewalRequest(RenewalRoundTrip* renewal_messages) { + ASSERT_NO_FATAL_FAILURE(renewal_messages->SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(renewal_messages->CreateDefaultResponse()); + } + + void LoadRenewal(RenewalRoundTrip* renewal_messages, + OEMCryptoResult expected_result) { + ASSERT_NO_FATAL_FAILURE(renewal_messages->EncryptAndSignResponse()); + ASSERT_EQ(expected_result, renewal_messages->LoadResponse()); + } + + ODK_TimerLimits timer_limits_; +}; + +// This class is for testing the generic crypto functionality. +class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { + protected: + // buffer_size_ must be a multiple of encryption block size, 16. We'll use a + // reasonable number of blocks for most of the tests. + OEMCryptoGenericCryptoTest() : buffer_size_(160) {} + + void SetUp() override { + OEMCryptoRefreshTest::SetUp(); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE( + license_messages_.CreateResponseWithGenericCryptoKeys()); + InitializeClearBuffer(); + } + + void InitializeClearBuffer() { + clear_buffer_.assign(buffer_size_, 0); + for (size_t i = 0; i < clear_buffer_.size(); i++) { + clear_buffer_[i] = 1 + i % 250; + } + for (size_t i = 0; i < wvoec::KEY_IV_SIZE; i++) { + iv_[i] = i; + } + } + + void ResizeBuffer(size_t new_size) { + buffer_size_ = new_size; + InitializeClearBuffer(); // Re-initialize the clear buffer. + } + + void EncryptAndLoadKeys() { + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + } + + // Encrypt the buffer with the specified key made in + // CreateResponseWithGenericCryptoKeys. + void EncryptBuffer(unsigned int key_index, const vector& in_buffer, + vector* out_buffer) { + EncryptBufferWithKey(session_.license().keys[key_index].key_data, in_buffer, + out_buffer); + } + // Encrypt the buffer with the specified key. + void EncryptBufferWithKey(const uint8_t* key_data, + const vector& in_buffer, + vector* out_buffer) { + AES_KEY aes_key; + ASSERT_EQ(0, AES_set_encrypt_key(key_data, AES_BLOCK_SIZE * 8, &aes_key)); + uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; + memcpy(iv_buffer, iv_, wvoec::KEY_IV_SIZE); + out_buffer->resize(in_buffer.size()); + ASSERT_GT(in_buffer.size(), 0u); + ASSERT_EQ(0u, in_buffer.size() % AES_BLOCK_SIZE); + AES_cbc_encrypt(in_buffer.data(), out_buffer->data(), in_buffer.size(), + &aes_key, iv_buffer, AES_ENCRYPT); + } + + // Sign the buffer with the specified key made in + // CreateResponseWithGenericCryptoKeys. + void SignBuffer(unsigned int key_index, const vector& in_buffer, + vector* signature) { + SignBufferWithKey(session_.license().keys[key_index].key_data, in_buffer, + signature); + } + + // Sign the buffer with the specified key. + void SignBufferWithKey(const uint8_t* key_data, + const vector& in_buffer, + vector* signature) { + unsigned int md_len = SHA256_DIGEST_LENGTH; + signature->resize(SHA256_DIGEST_LENGTH); + HMAC(EVP_sha256(), key_data, wvoec::MAC_KEY_SIZE, in_buffer.data(), + in_buffer.size(), signature->data(), &md_len); + } + + OEMCryptoResult GenericEncrypt(const uint8_t* key_handle, + size_t key_handle_length, + const uint8_t* clear_buffer, + size_t clear_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_encrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Encrypt(key_handle, key_handle_length, + clear_buffer, clear_buffer_length, iv, + algorithm, out_buffer); + } + + OEMCryptoResult GenericDecrypt( + const uint8_t* key_handle, size_t key_handle_length, + const uint8_t* encrypted_buffer, size_t encrypted_buffer_length, + const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_decrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(encrypted_buffer), + encrypted_buffer_length); + } + return OEMCrypto_Generic_Decrypt(key_handle, key_handle_length, + encrypted_buffer, encrypted_buffer_length, + iv, algorithm, out_buffer); + } + + OEMCryptoResult GenericVerify(const uint8_t* key_handle, + size_t key_handle_length, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(signature), + signature_length); + } + return OEMCrypto_Generic_Verify(key_handle, key_handle_length, clear_buffer, + clear_buffer_length, algorithm, signature, + signature_length); + } + + OEMCryptoResult GenericSign(const uint8_t* key_handle, + size_t key_handle_length, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, uint8_t* signature, + size_t* signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_sign_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Sign(key_handle, key_handle_length, clear_buffer, + clear_buffer_length, algorithm, signature, + signature_length); + } + + // This asks OEMCrypto to encrypt with the specified key, and expects a + // failure. + void BadEncrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, + size_t buffer_length) { + OEMCryptoResult sts; + vector expected_encrypted; + EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); + vector key_handle; + sts = GetKeyHandleIntoVector( + session_.session_id(), session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector encrypted(buffer_length); + sts = GenericEncrypt(key_handle.data(), key_handle.size(), + clear_buffer_.data(), buffer_length, iv_, algorithm, + encrypted.data()); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + expected_encrypted.resize(buffer_length); + EXPECT_NE(encrypted, expected_encrypted); + } + + // This asks OEMCrypto to decrypt with the specified key, and expects a + // failure. + void BadDecrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, + size_t buffer_length) { + OEMCryptoResult sts; + vector encrypted; + EncryptBuffer(key_index, clear_buffer_, &encrypted); + vector key_handle; + sts = GetKeyHandleIntoVector( + session_.session_id(), session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector resultant(encrypted.size()); + sts = GenericDecrypt(key_handle.data(), key_handle.size(), encrypted.data(), + buffer_length, iv_, algorithm, resultant.data()); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(clear_buffer_, resultant); + } + + // This asks OEMCrypto to sign with the specified key, and expects a + // failure. + void BadSign(unsigned int key_index, OEMCrypto_Algorithm algorithm) { + OEMCryptoResult sts; + vector expected_signature; + SignBuffer(key_index, clear_buffer_, &expected_signature); + + vector key_handle; + sts = GetKeyHandleIntoVector( + session_.session_id(), session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; + vector signature(SHA256_DIGEST_LENGTH); + sts = GenericSign(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), algorithm, + signature.data(), &signature_length); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + EXPECT_NE(signature, expected_signature); + } + + // This asks OEMCrypto to verify a signature with the specified key, and + // expects a failure. + void BadVerify(unsigned int key_index, OEMCrypto_Algorithm algorithm, + size_t signature_size, bool alter_data) { + OEMCryptoResult sts; + vector signature; + SignBuffer(key_index, clear_buffer_, &signature); + if (alter_data) { + signature[0] ^= 42; + } + if (signature.size() < signature_size) { + signature.resize(signature_size); + } + + vector key_handle; + sts = GetKeyHandleIntoVector( + session_.session_id(), session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CENC, key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + sts = GenericVerify(key_handle.data(), key_handle.size(), + clear_buffer_.data(), clear_buffer_.size(), algorithm, + signature.data(), signature_size); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + } + + // This must be a multiple of encryption block size. + size_t buffer_size_; + vector clear_buffer_; + vector encrypted_buffer_; + uint8_t iv_[wvoec::KEY_IV_SIZE]; +}; + +class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { + public: + void SetUp() override { OEMCryptoGenericCryptoTest::SetUp(); } + + virtual void ShutDown() { + ASSERT_NO_FATAL_FAILURE(session_.close()); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); + } + + virtual void Restart() { + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + (void)OEMCrypto_SetMaxAPIVersion(kCurrentAPI); + (void)OEMCrypto_EnterTestMode(); + EnsureTestROT(); + ASSERT_NO_FATAL_FAILURE(session_.open()); + } + + void PrintDotsWhileSleep(int64_t total_seconds, int64_t interval_seconds) { + int64_t dot_time = interval_seconds; + int64_t elapsed_time = 0; + const int64_t start_time = wvutil::Clock().GetCurrentTime(); + do { + wvutil::TestSleep::Sleep(1); + elapsed_time = wvutil::Clock().GetCurrentTime() - start_time; + if (elapsed_time >= dot_time) { + cout << "."; + cout.flush(); + dot_time += interval_seconds; + } + } while (elapsed_time < total_seconds); + cout << endl; + } + + OEMCryptoResult LoadUsageTableHeader( + const vector& encrypted_usage_header) { + return OEMCrypto_LoadUsageTableHeader(encrypted_usage_header.data(), + encrypted_usage_header.size()); + } +}; + +} // namespace wvoec + +#endif // CDM_OEMCRYPTO_USAGE_TABLE_TEST_ \ No newline at end of file diff --git a/oemcrypto/test/ota_keybox_test.cpp b/oemcrypto/test/ota_keybox_test.cpp index 359da3a..d1a9464 100644 --- a/oemcrypto/test/ota_keybox_test.cpp +++ b/oemcrypto/test/ota_keybox_test.cpp @@ -13,6 +13,7 @@ #include "oec_key_deriver.h" #include "oec_session_util.h" #include "oec_test_data.h" +#include "oemcrypto_basic_test.h" #include "oemcrypto_session_tests_helper.h" #include "oemcrypto_types.h" #include "platform.h" @@ -140,19 +141,6 @@ constexpr size_t kInitialOtaKeyboxRequestSize = 8 * 1024; // 8 kB. // |use_test_key| parameter of OEMCrypto_GenerateOTARequest() is true. constexpr uint32_t kUseTestKey = 1; -// TODO(fredgc): duplicate code. Move to common util package. -// Return a printable string from data. If all the characters are printable, -// then just use the string. Otherwise, convert to hex. -std::string MaybeHex(const uint8_t* data, size_t length) { - for (size_t i = 0; i < length; i++) { - if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); - } - return std::string(reinterpret_cast(data), length); -} -std::string MaybeHex(const std::vector& data) { - return MaybeHex(data.data(), data.size()); -} - std::vector GetModelKey(const std::vector& device_id) { std::vector keymint_key( TestKeyPKCS8, TestKeyPKCS8 + wvutil::ArraySize(TestKeyPKCS8)); diff --git a/oemcrypto/util/include/oemcrypto_key_deriver.h b/oemcrypto/util/include/oemcrypto_key_deriver.h index 4a52547..fdcf3ec 100644 --- a/oemcrypto/util/include/oemcrypto_key_deriver.h +++ b/oemcrypto/util/include/oemcrypto_key_deriver.h @@ -47,6 +47,11 @@ class KeyDeriver { bool DeriveEncryptionKey(const std::vector& enc_key_context, std::vector* enc_key); + // Derive renewed device key. Use on KeyDeriver initialized with old device + // key. |context| should be just the context field, eg A_priv+CA_token. + bool DeriveRenewedDeviceKey(const std::vector& context, + std::vector* renewed_device_key); + ~KeyDeriver() {} private: diff --git a/oemcrypto/util/include/oemcrypto_key_handle.h b/oemcrypto/util/include/oemcrypto_key_handle.h new file mode 100644 index 0000000..9db9043 --- /dev/null +++ b/oemcrypto/util/include/oemcrypto_key_handle.h @@ -0,0 +1,63 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Implements utility functions for serializing and deserializing the fake key +// handles used by the Ref and Testbed. +// +#ifndef WVOEC_UTIL_KEY_HANDLE_H_ +#define WVOEC_UTIL_KEY_HANDLE_H_ + +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "log.h" + +namespace wvoec { +namespace util { +// Size of a key handle, which for this implementation is just a session ID. +constexpr size_t kKeyHandleSize = sizeof(OEMCrypto_SESSION); + +OEMCryptoResult SerializeSessionToKeyHandle(OEMCrypto_SESSION session, + uint8_t* key_handle, + size_t* key_handle_length) { + if (key_handle_length == nullptr) { + LOGE("Null key handle length"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (key_handle == nullptr || *key_handle_length < kKeyHandleSize) { + *key_handle_length = kKeyHandleSize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + *key_handle_length = kKeyHandleSize; + memcpy(key_handle, &session, kKeyHandleSize); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult DeserializeKeyHandleToSession(const uint8_t* key_handle, + size_t key_handle_length, + OEMCrypto_SESSION* session) { + if (key_handle == nullptr) { + LOGE("Null key handle"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session == nullptr) { + LOGE("Null session"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (key_handle_length != kKeyHandleSize) { + LOGE("Invalid key handle length"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + memcpy(session, key_handle, kKeyHandleSize); + return OEMCrypto_SUCCESS; +} +} // namespace util +} // namespace wvoec +#endif // WVOEC_UTIL_KEY_HANDLE_H_ diff --git a/oemcrypto/util/include/oemcrypto_rsa_key.h b/oemcrypto/util/include/oemcrypto_rsa_key.h index d66f527..35b93ab 100644 --- a/oemcrypto/util/include/oemcrypto_rsa_key.h +++ b/oemcrypto/util/include/oemcrypto_rsa_key.h @@ -122,6 +122,8 @@ class RsaPublicKey { // private equivalent of this public key. // The signature algorithm can be specified via the |algorithm| field. // See RsaSignatureAlgorithm for details on each algorithm. + // For RSASSA-PSS, the hash algorithm can be specified via |hash_algorithm|. + // This parameter is ignored for other signature algorithms. // // Returns: // OEMCrypto_SUCCESS if signature is valid @@ -129,15 +131,17 @@ class RsaPublicKey { // OEMCrypto_ERROR_UNKNOWN_FAILURE if any error occurs OEMCryptoResult VerifySignature( const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, - RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + size_t signature_length, RsaSignatureAlgorithm algorithm = kRsaPssDefault, + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1) const; OEMCryptoResult VerifySignature( const std::string& message, const std::string& signature, - RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + RsaSignatureAlgorithm algorithm = kRsaPssDefault, + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1) const; OEMCryptoResult VerifySignature( const std::vector& message, const std::vector& signature, - RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + RsaSignatureAlgorithm algorithm = kRsaPssDefault, + OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1) const; // Encrypts the OEMCrypto session key used for deriving other keys. // On success, |enc_session_key_size| is populated with the number @@ -195,10 +199,10 @@ class RsaPublicKey { bool InitFromSslHandle(const RSA* rsa_handle, uint32_t allowed_schemes); // Signature specialization functions. - OEMCryptoResult VerifySignaturePss(const uint8_t* message, - size_t message_length, - const uint8_t* signature, - size_t signature_length) const; + OEMCryptoResult VerifySignaturePss( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, + OEMCrypto_SignatureHashAlgorithm hash_algorithm) const; OEMCryptoResult VerifySignaturePkcs1Cast(const uint8_t* message, size_t message_length, const uint8_t* signature, @@ -268,6 +272,13 @@ class RsaPrivateKey { // Returns an empty vector on error. std::vector Serialize() const; + // Serializes the key's private exponent in network-byte-order + // using I2OSP primitive as defined by RFC3447 Section 4.1. The + // exact length of the exponent will depend on the exponents value, + // not the modulus size. + // Returns an empty vector on error. + std::vector GetPrivateExponent() const; + // Signs the provided |message| using the RSA signing algorithm // specified by |algorithm|. See RsaSignatureAlgorithm for // details on each algorithm. diff --git a/oemcrypto/util/src/oemcrypto_key_deriver.cpp b/oemcrypto/util/src/oemcrypto_key_deriver.cpp index 2d65a29..df8d8fb 100644 --- a/oemcrypto/util/src/oemcrypto_key_deriver.cpp +++ b/oemcrypto/util/src/oemcrypto_key_deriver.cpp @@ -40,6 +40,31 @@ bool Derive256Key(Cmac* cmac, uint8_t counter_base, const uint8_t* ctx, } return Derive128KeyAppend(cmac, counter_base + 1, ctx, ctx_size, derived_key); } + +bool NistKdf(Cmac* cmac, const std::vector& label, + const std::vector& context, size_t bits, + std::vector* renewed_device_key) { + const std::vector size_bits_big_endian = { + static_cast(bits >> 24), static_cast(bits >> 16), + static_cast(bits >> 8), static_cast(bits)}; + const size_t kAesBlockSizeBits = 16 * 8; + + if (bits % kAesBlockSizeBits != 0) return false; + if (renewed_device_key == nullptr) { + return false; + } + renewed_device_key->clear(); + bool res = false; + for (size_t counter = 0; counter < bits / kAesBlockSizeBits; counter++) { + cmac->Reset(); + res = cmac->Update(counter + 1) && cmac->Update(label) && + cmac->Update(0x00) && cmac->Update(context) && + cmac->Update(size_bits_big_endian) && + cmac->FinalizeAppend(renewed_device_key); + if (!res) break; + } + return res; +} } // namespace // static @@ -150,5 +175,20 @@ bool KeyDeriver::DeriveEncryptionKey( return DeriveEncryptionKey(enc_key_context.data(), enc_key_context.size(), enc_key); } + +bool KeyDeriver::DeriveRenewedDeviceKey( + const std::vector& context, + std::vector* renewed_device_key) { + if (renewed_device_key == nullptr) { + LOGE("Output key buffer is null"); + return false; + } + const std::string kKeyboxRenewalLabel = "Keyboxv4"; + const std::vector kKeyboxRenewalLabelVec(kKeyboxRenewalLabel.begin(), + kKeyboxRenewalLabel.end()); + + return NistKdf(cmac_.get(), kKeyboxRenewalLabelVec, context, 0x80, + renewed_device_key); +} } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/src/oemcrypto_rsa_key.cpp b/oemcrypto/util/src/oemcrypto_rsa_key.cpp index f77b2c1..0c4ce06 100644 --- a/oemcrypto/util/src/oemcrypto_rsa_key.cpp +++ b/oemcrypto/util/src/oemcrypto_rsa_key.cpp @@ -326,6 +326,27 @@ bool RsaPublicKey::IsMatchingPrivateKey( return RsaKeysAreMatchingPair(GetRsaKey(), private_key.GetRsaKey()); } +std::vector RsaPrivateKey::GetPrivateExponent() const { + const BIGNUM* d = RSA_get0_d(key_); + if (d == nullptr) { + LOGE("Private exponent must not be null"); + return {}; + } + // Get the required length for the data. + const size_t length = BN_num_bytes(d); + if (length <= 0) { + LOGE("Private exponent length must be positive"); + return {}; + } + std::vector serialized_private_exponent(length, 0); + if (static_cast(BN_bn2bin(d, serialized_private_exponent.data())) != + length) { + LOGE("Failed to convert the private exponent"); + return {}; + } + return serialized_private_exponent; +} + OEMCryptoResult RsaPublicKey::Serialize(uint8_t* buffer, size_t* buffer_size) const { if (buffer_size == nullptr) { @@ -378,7 +399,8 @@ std::vector RsaPublicKey::Serialize() const { OEMCryptoResult RsaPublicKey::VerifySignature( const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, RsaSignatureAlgorithm algorithm) const { + size_t signature_length, RsaSignatureAlgorithm algorithm, + OEMCrypto_SignatureHashAlgorithm hash_algorithm) const { if (signature == nullptr || signature_length == 0) { LOGE("Signature is missing"); return OEMCrypto_ERROR_INVALID_CONTEXT; @@ -390,7 +412,7 @@ OEMCryptoResult RsaPublicKey::VerifySignature( switch (algorithm) { case kRsaPssDefault: return VerifySignaturePss(message, message_length, signature, - signature_length); + signature_length, hash_algorithm); case kRsaPkcs1Cast: return VerifySignaturePkcs1Cast(message, message_length, signature, signature_length); @@ -401,7 +423,8 @@ OEMCryptoResult RsaPublicKey::VerifySignature( OEMCryptoResult RsaPublicKey::VerifySignature( const std::string& message, const std::string& signature, - RsaSignatureAlgorithm algorithm) const { + RsaSignatureAlgorithm algorithm, + OEMCrypto_SignatureHashAlgorithm hash_algorithm) const { if (signature.empty()) { LOGE("Signature should not be empty"); return OEMCrypto_ERROR_INVALID_CONTEXT; @@ -409,18 +432,19 @@ OEMCryptoResult RsaPublicKey::VerifySignature( return VerifySignature(reinterpret_cast(message.data()), message.size(), reinterpret_cast(signature.data()), - signature.size(), algorithm); + signature.size(), algorithm, hash_algorithm); } OEMCryptoResult RsaPublicKey::VerifySignature( const std::vector& message, const std::vector& signature, - RsaSignatureAlgorithm algorithm) const { + RsaSignatureAlgorithm algorithm, + OEMCrypto_SignatureHashAlgorithm hash_algorithm) const { if (signature.empty()) { LOGE("Signature should not be empty"); return OEMCrypto_ERROR_INVALID_CONTEXT; } return VerifySignature(message.data(), message.size(), signature.data(), - signature.size(), algorithm); + signature.size(), algorithm, hash_algorithm); } OEMCryptoResult RsaPublicKey::EncryptSessionKey( @@ -643,7 +667,8 @@ bool RsaPublicKey::InitFromSslHandle(const RSA* rsa_handle, OEMCryptoResult RsaPublicKey::VerifySignaturePss( const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length) const { + size_t signature_length, + OEMCrypto_SignatureHashAlgorithm hash_algorithm) const { // Step 0: Ensure the signature algorithm is supported by key. if (!(allowed_schemes_ & kSign_RSASSA_PSS)) { LOGE("RSA key cannot verify using PSS"); @@ -659,14 +684,34 @@ OEMCryptoResult RsaPublicKey::VerifySignaturePss( LOGE("Failed to set PKEY RSA key"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // Step 2a: Setup a EVP MD CTX for PSS Verification. + // Step 2a: Choose the correct digest algorithm. + const EVP_MD* digest = nullptr; + switch (hash_algorithm) { + case OEMCrypto_SHA1: + digest = EVP_sha1(); + break; + case OEMCrypto_SHA2_256: + digest = EVP_sha256(); + break; + case OEMCrypto_SHA2_384: + digest = EVP_sha384(); + break; + case OEMCrypto_SHA2_512: + digest = EVP_sha512(); + break; + } + if (digest == nullptr) { + LOGE("Unrecognized hash algorithm %d", hash_algorithm); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Step 2b: Setup an EVP MD CTX for PSS Verification. ScopedEvpMdCtx md_ctx = EVP_MD_CTX_new(); if (!md_ctx) { LOGE("Failed to allocate MD CTX"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } EVP_PKEY_CTX* pkey_ctx = nullptr; // Ownership is maintained by |md_ctx| - int res = EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), nullptr, + int res = EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, digest, nullptr, pkey.get()); if (res != 1) { LOGE("Failed to initialize MD CTX for verification"); @@ -676,7 +721,7 @@ OEMCryptoResult RsaPublicKey::VerifySignaturePss( LOGE("PKEY CTX is unexpectedly null"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // Step 2b: Configure OEMCrypto RSASSA-PSS options. + // Step 2c: Configure OEMCrypto RSASSA-PSS options. res = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING); if (res != 1) { LOGE("Failed to set PSS padding"); diff --git a/oemcrypto/util/test/oem_cert_test.cpp b/oemcrypto/util/test/oem_cert_test.cpp index 234d31c..e4dcd5d 100644 --- a/oemcrypto/util/test/oem_cert_test.cpp +++ b/oemcrypto/util/test/oem_cert_test.cpp @@ -2,9 +2,10 @@ // source code may only be used and distributed under the Widevine License // Agreement. -#include "oem_cert.h" +#include "oem_cert_test.h" -namespace wvoec_ref { +namespace wvoec { +namespace util { namespace { const uint32_t kTestOemSystemId = 7913; @@ -529,4 +530,5 @@ const uint8_t* kOEMPublicCert = kTestOemPublicCert; const size_t kOEMPrivateKeySize = kTestOemPrivateKeySize; const size_t kOEMPublicCertSize = kTestOemPublicCertSize; -} // namespace wvoec_ref +} // namespace util +} // namespace wvoec diff --git a/oemcrypto/util/test/oem_cert_test.h b/oemcrypto/util/test/oem_cert_test.h new file mode 100644 index 0000000..a19b952 --- /dev/null +++ b/oemcrypto/util/test/oem_cert_test.h @@ -0,0 +1,27 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// This header is used to access the testing OEM certificate. +#ifndef OEM_CERT_TEST_H_ +#define OEM_CERT_TEST_H_ + +#include +#include + +namespace wvoec { +namespace util { + +// Refer to the following in main modules +extern const uint32_t kOEMSystemId; + +extern const uint8_t* kOEMPrivateKey; +extern const uint8_t* kOEMPublicCert; + +extern const size_t kOEMPrivateKeySize; +extern const size_t kOEMPublicCertSize; + +} // namespace util +} // namespace wvoec + +#endif // OEM_CERT_TEST_H_ diff --git a/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp b/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp index 2f220e1..6239045 100644 --- a/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp +++ b/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp @@ -7,16 +7,12 @@ #include #include "OEMCryptoCENCCommon.h" -#include "oem_cert.h" +#include "oem_cert_test.h" #include "oemcrypto_oem_cert.h" #include "oemcrypto_rsa_key.h" namespace wvoec { namespace util { -using wvoec_ref::kOEMPrivateKey; -using wvoec_ref::kOEMPrivateKeySize; -using wvoec_ref::kOEMPublicCert; -using wvoec_ref::kOEMPublicCertSize; namespace { const std::vector kOEMPrivateKeyVector(kOEMPrivateKey, kOEMPrivateKey + diff --git a/oemcrypto/util/test/oemcrypto_ref_test_utils.h b/oemcrypto/util/test/oemcrypto_ref_test_utils.h index fccc58f..3f62567 100644 --- a/oemcrypto/util/test/oemcrypto_ref_test_utils.h +++ b/oemcrypto/util/test/oemcrypto_ref_test_utils.h @@ -7,6 +7,7 @@ #ifndef WVOEC_UTIL_REF_TEST_UTILS_H_ #define WVOEC_UTIL_REF_TEST_UTILS_H_ +#include #include #include diff --git a/util/include/error_string_util.h b/util/include/error_string_util.h new file mode 100644 index 0000000..8be4eaa --- /dev/null +++ b/util/include/error_string_util.h @@ -0,0 +1,11 @@ +#ifndef ERROR_STRING_UTIL_H_ +#define ERROR_STRING_UTIL_H_ + +#include + +namespace wvutil { + +const std::string OEMCryptoResultToString(int oemcrypto_result); + +} // namespace wvutil +#endif // ERROR_STRING_UTIL_H_ diff --git a/util/include/file_store.h b/util/include/file_store.h index 8594356..6bb1773 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -28,7 +28,7 @@ static const std::string kOemCertificateFileName = "oemcert.bin"; static const std::string kOemCertificateFileNamePrefix = "oemcert_"; // File class. The implementation is platform dependent. -class CORE_UTIL_EXPORT File { +class File { public: File() {} virtual ~File() {} @@ -39,7 +39,7 @@ class CORE_UTIL_EXPORT File { CORE_DISALLOW_COPY_AND_ASSIGN(File); }; -class CORE_UTIL_EXPORT FileSystem { +class FileSystem { public: FileSystem(); FileSystem(const std::string& origin, void* extra_data); diff --git a/util/include/log.h b/util/include/log.h index f4d5e72..2854956 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -77,31 +77,34 @@ struct LoggingUidSetter { // This function is supplied for cases where the system layer does not // initialize logging. This is also needed to initialize logging in // unit tests. -CORE_UTIL_EXPORT void InitLogging(); +void InitLogging(); #ifdef __GNUC__ -[[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file, - const char* function, - int line, - LogPriority level, - const char* fmt, ...); -#else -CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, - LogPriority level, const char* fmt, ...); +[[gnu::format(printf, 5, 6)]] #endif +void Log(const char* file, const char* function, int line, + LogPriority level, const char* fmt, ...); // Log APIs -#ifndef LOGE -# define LOGE(...) \ +#ifdef CDM_DISABLE_LOGGING +# define LOGE(...) (void)0 +# define LOGW(...) (void)0 +# define LOGI(...) (void)0 +# define LOGD(...) (void)0 +# define LOGV(...) (void)0 +#else +# ifndef LOGE +# define LOGE(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_ERROR, __VA_ARGS__) -# define LOGW(...) \ +# define LOGW(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_WARN, __VA_ARGS__) -# define LOGI(...) \ +# define LOGI(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_INFO, __VA_ARGS__) -# define LOGD(...) \ +# define LOGD(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_DEBUG, __VA_ARGS__) -# define LOGV(...) \ +# define LOGV(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_VERBOSE, __VA_ARGS__) +# endif #endif } // namespace wvutil diff --git a/util/include/platform.h b/util/include/platform.h index effc514..d101dd6 100644 --- a/util/include/platform.h +++ b/util/include/platform.h @@ -21,7 +21,7 @@ using ssize_t = SSIZE_T; inline void sleep(int seconds) { Sleep(seconds * 1000); } -CORE_UTIL_EXPORT int setenv(const char* key, const char* value, int overwrite); +int setenv(const char* key, const char* value, int overwrite); #else # include # include diff --git a/util/include/rw_lock.h b/util/include/rw_lock.h index 5ea3a97..40d7902 100644 --- a/util/include/rw_lock.h +++ b/util/include/rw_lock.h @@ -16,7 +16,7 @@ namespace wvutil { // A simple reader-writer mutex implementation that mimics the one from C++17 -class CORE_UTIL_EXPORT shared_mutex { +class shared_mutex { public: shared_mutex() : reader_count_(0), has_writer_(false) {} ~shared_mutex(); diff --git a/util/include/string_conversions.h b/util/include/string_conversions.h index e5944bd..461ef41 100644 --- a/util/include/string_conversions.h +++ b/util/include/string_conversions.h @@ -15,53 +15,46 @@ namespace wvutil { // ASCII hex to Binary conversion. -CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& b); -CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& label, - const std::string& b); -CORE_UTIL_EXPORT std::string a2bs_hex(const std::string& b); +std::vector a2b_hex(const std::string& b); +std::vector a2b_hex(const std::string& label, + const std::string& b); +std::string a2bs_hex(const std::string& b); // Binary to ASCII hex conversion. The default versions limit output to 2k to // protect us from log spam. The unlimited version has no length limit. -CORE_UTIL_EXPORT std::string b2a_hex(const std::vector& b); -CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::vector& b); -CORE_UTIL_EXPORT std::string b2a_hex(const std::string& b); -CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::string& b); -CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, size_t size); -CORE_UTIL_EXPORT std::string UnlimitedHexEncode(const uint8_t* bytes, - size_t size); +std::string b2a_hex(const std::vector& b); +std::string unlimited_b2a_hex(const std::vector& b); +std::string b2a_hex(const std::string& b); +std::string unlimited_b2a_hex(const std::string& b); +std::string HexEncode(const uint8_t* bytes, size_t size); +std::string UnlimitedHexEncode(const uint8_t* bytes, size_t size); // Base64 encoding/decoding. // Converts binary data into the ASCII Base64 character set and vice // versa using the encoding rules defined in RFC4648 section 4. -CORE_UTIL_EXPORT std::string Base64Encode( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64Encode(const std::string& bin_input); -CORE_UTIL_EXPORT std::vector Base64Decode( - const std::string& bin_input); +std::string Base64Encode(const std::vector& bin_input); +std::string Base64Encode(const std::string& bin_input); +std::vector Base64Decode(const std::string& bin_input); // URL-Safe Base64 encoding/decoding. // Converts binary data into the URL/Filename safe ASCII Base64 // character set and vice versa using the encoding rules defined in // RFC4648 section 5. -CORE_UTIL_EXPORT std::string Base64SafeEncode( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncode(const std::string& bin_input); -CORE_UTIL_EXPORT std::vector Base64SafeDecode( - const std::string& bin_input); +std::string Base64SafeEncode(const std::vector& bin_input); +std::string Base64SafeEncode(const std::string& bin_input); +std::vector Base64SafeDecode(const std::string& bin_input); // URL-Safe Base64 encoding without padding. // Similar to Base64SafeEncode(), without any padding character '=' // at the end. -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::string& bin_input); +std::string Base64SafeEncodeNoPad(const std::vector& bin_input); +std::string Base64SafeEncodeNoPad(const std::string& bin_input); // Host to Network/Network to Host conversion. -CORE_UTIL_EXPORT int64_t htonll64(int64_t x); -CORE_UTIL_EXPORT inline int64_t ntohll64(int64_t x) { return htonll64(x); } +int64_t htonll64(int64_t x); +inline int64_t ntohll64(int64_t x) { return htonll64(x); } // Encode unsigned integer into a big endian formatted string. -CORE_UTIL_EXPORT std::string EncodeUint32(uint32_t u); +std::string EncodeUint32(uint32_t u); } // namespace wvutil diff --git a/util/include/string_format.h b/util/include/string_format.h new file mode 100644 index 0000000..62f9fd9 --- /dev/null +++ b/util/include/string_format.h @@ -0,0 +1,18 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +#ifndef WVCDM_UTIL_STRING_FORMAT_H_ +#define WVCDM_UTIL_STRING_FORMAT_H_ + +#include + +namespace wvutil { + +#ifdef __GNUC__ +[[gnu::format(printf, 2, 3)]] +#endif +bool FormatString(std::string* out, const char* fmt, ...); + +} // namespace wvutil + +#endif // WVCDM_UTIL_STRING_FORMAT_H_ diff --git a/util/include/util_common.h b/util/include/util_common.h index 7b28c48..b1ddc16 100644 --- a/util/include/util_common.h +++ b/util/include/util_common.h @@ -9,23 +9,11 @@ #ifdef _WIN32 -# ifdef CORE_UTIL_IMPLEMENTATION -# define CORE_UTIL_EXPORT __declspec(dllexport) -# else -# define CORE_UTIL_EXPORT __declspec(dllimport) -# endif - # define CORE_UTIL_IGNORE_DEPRECATED # define CORE_UTIL_RESTORE_WARNINGS #else -# ifdef CORE_UTIL_IMPLEMENTATION -# define CORE_UTIL_EXPORT __attribute__((visibility("default"))) -# else -# define CORE_UTIL_EXPORT -# endif - # ifdef __GNUC__ # define CORE_UTIL_IGNORE_DEPRECATED \ _Pragma("GCC diagnostic push") \ diff --git a/util/libcrypto_dependency.gypi b/util/libcrypto_dependency.gypi index c456cec..8bf8ccf 100644 --- a/util/libcrypto_dependency.gypi +++ b/util/libcrypto_dependency.gypi @@ -3,17 +3,15 @@ # Agreement. { 'conditions': [ - [ - 'privacy_crypto_impl=="openssl"', { - 'libraries': [ - '-lcrypto', - ], - }, # privacy_crypto_impl=="openssl" - 'privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { - 'dependencies': [ - '<(boringssl_libcrypto_path)', - ], # dependencies - }, # privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple" - ], + ['privacy_crypto_impl=="openssl"', { + 'libraries': [ + '-lcrypto', + ], + }], + ['privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { + 'dependencies': [ + '<(boringssl_libcrypto_path)', + ], # dependencies + }], ], # conditions } diff --git a/util/libssl_dependency.gypi b/util/libssl_dependency.gypi index 837c4ce..1261570 100644 --- a/util/libssl_dependency.gypi +++ b/util/libssl_dependency.gypi @@ -3,18 +3,16 @@ # Agreement. { 'conditions': [ - [ - 'privacy_crypto_impl=="openssl"', { - 'libraries': [ - '-lcrypto', - '-lssl', - ], - }, # privacy_crypto_impl=="openssl" - 'privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { - 'dependencies': [ - '<(boringssl_libssl_path)', - ], # dependencies - }, # privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple" - ], + ['privacy_crypto_impl=="openssl"', { + 'libraries': [ + '-lcrypto', + '-lssl', + ], + }], + ['privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { + 'dependencies': [ + '<(boringssl_libssl_path)', + ], # dependencies + }], ], # conditions } diff --git a/util/src/error_string_util.cpp b/util/src/error_string_util.cpp new file mode 100644 index 0000000..d70a6a8 --- /dev/null +++ b/util/src/error_string_util.cpp @@ -0,0 +1,171 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// + +#include "error_string_util.h" + +#include "OEMCryptoCENC.h" +#include "wv_cdm_types.h" + +namespace wvutil { +const std::string OEMCryptoResultToString(int oemcrypto_result) { + switch (oemcrypto_result) { + case OEMCrypto_SUCCESS: + return "SUCCESS"; + case OEMCrypto_ERROR_INIT_FAILED: + return "INIT_FAILED"; + case OEMCrypto_ERROR_TERMINATE_FAILED: + return "TERMINATE_FAILED"; + case OEMCrypto_ERROR_OPEN_FAILURE: + return "OPEN_FAILURE"; + case OEMCrypto_ERROR_CLOSE_FAILURE: + return "CLOSE_FAILURE"; + case OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED: + return "ENTER_SECURE_PLAYBACK_FAILED"; + case OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED: + return "EXIT_SECURE_PLAYBACK_FAILED"; + case OEMCrypto_ERROR_SHORT_BUFFER: + return "SHORT_BUFFER"; + case OEMCrypto_ERROR_NO_DEVICE_KEY: + return "NO_DEVICE_KEY"; + case OEMCrypto_ERROR_NO_ASSET_KEY: + return "NO_ASSET_KEY"; + case OEMCrypto_ERROR_KEYBOX_INVALID: + return "KEYBOX_INVALID"; + case OEMCrypto_ERROR_NO_KEYDATA: + return "NO_KEYDATA"; + case OEMCrypto_ERROR_NO_CW: + return "NO_CW"; + case OEMCrypto_ERROR_DECRYPT_FAILED: + return "DECRYPT_FAILED"; + case OEMCrypto_ERROR_WRITE_KEYBOX: + return "WRITE_KEYBOX"; + case OEMCrypto_ERROR_WRAP_KEYBOX: + return "WRAP_KEYBOX"; + case OEMCrypto_ERROR_BAD_MAGIC: + return "BAD_MAGIC"; + case OEMCrypto_ERROR_BAD_CRC: + return "BAD_CRC"; + case OEMCrypto_ERROR_NO_DEVICEID: + return "NO_DEVICEID"; + case OEMCrypto_ERROR_RNG_FAILED: + return "RNG_FAILED"; + case OEMCrypto_ERROR_RNG_NOT_SUPPORTED: + return "RNG_NOT_SUPPORTED"; + case OEMCrypto_ERROR_SETUP: + return "SETUP"; + case OEMCrypto_ERROR_OPEN_SESSION_FAILED: + return "OPEN_SESSION_FAILED"; + case OEMCrypto_ERROR_CLOSE_SESSION_FAILED: + return "CLOSE_SESSION_FAILED"; + case OEMCrypto_ERROR_INVALID_SESSION: + return "INVALID_SESSION"; + case OEMCrypto_ERROR_NOT_IMPLEMENTED: + return "NOT_IMPLEMENTED"; + case OEMCrypto_ERROR_NO_CONTENT_KEY: + return "NO_CONTENT_KEY"; + case OEMCrypto_ERROR_CONTROL_INVALID: + return "CONTROL_INVALID"; + case OEMCrypto_ERROR_UNKNOWN_FAILURE: + return "UNKNOWN_FAILURE"; + case OEMCrypto_ERROR_INVALID_CONTEXT: + return "INVALID_CONTEXT"; + case OEMCrypto_ERROR_SIGNATURE_FAILURE: + return "SIGNATURE_FAILURE"; + case OEMCrypto_ERROR_TOO_MANY_SESSIONS: + return "TOO_MANY_SESSIONS"; + case OEMCrypto_ERROR_INVALID_NONCE: + return "INVALID_NONCE"; + case OEMCrypto_ERROR_TOO_MANY_KEYS: + return "TOO_MANY_KEYS"; + case OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED: + return "DEVICE_NOT_RSA_PROVISIONED"; + case OEMCrypto_ERROR_INVALID_RSA_KEY: + return "INVALID_RSA_KEY"; + case OEMCrypto_ERROR_KEY_EXPIRED: + return "KEY_EXPIRED"; + case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES: + return "INSUFFICIENT_RESOURCES"; + case OEMCrypto_ERROR_INSUFFICIENT_HDCP: + return "INSUFFICIENT_HDCP"; + case OEMCrypto_ERROR_BUFFER_TOO_LARGE: + return "BUFFER_TOO_LARGE"; + case OEMCrypto_WARNING_GENERATION_SKEW: + return "OEMCrypto_WARNING_GENERATION_SKEW"; + case OEMCrypto_ERROR_GENERATION_SKEW: + return "GENERATION_SKEW"; + case OEMCrypto_LOCAL_DISPLAY_ONLY: + return "OEMCrypto_LOCAL_DISPLAY_ONLY"; + case OEMCrypto_ERROR_ANALOG_OUTPUT: + return "ANALOG_OUTPUT"; + case OEMCrypto_ERROR_WRONG_PST: + return "WRONG_PST"; + case OEMCrypto_ERROR_WRONG_KEYS: + return "WRONG_KEYS"; + case OEMCrypto_ERROR_MISSING_MASTER: + return "MISSING_MASTER"; + case OEMCrypto_ERROR_LICENSE_INACTIVE: + return "LICENSE_INACTIVE"; + case OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE: + return "ENTRY_NEEDS_UPDATE"; + case OEMCrypto_ERROR_ENTRY_IN_USE: + return "ENTRY_IN_USE"; + case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE: + return "USAGE_TABLE_UNRECOVERABLE"; + case OEMCrypto_KEY_NOT_LOADED: + return "OEMCrypto_KEY_NOT_LOADED"; + case OEMCrypto_KEY_NOT_ENTITLED: + return "OEMCrypto_KEY_NOT_ENTITLED"; + case OEMCrypto_ERROR_BAD_HASH: + return "BAD_HASH"; + case OEMCrypto_ERROR_OUTPUT_TOO_LARGE: + return "OUTPUT_TOO_LARGE"; + case OEMCrypto_ERROR_SESSION_LOST_STATE: + return "SESSION_LOST_STATE"; + case OEMCrypto_ERROR_SYSTEM_INVALIDATED: + return "SYSTEM_INVALIDATED"; + case OEMCrypto_ERROR_LICENSE_RELOAD: + return "LICENSE_RELOAD"; + case OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES: + return "MULTIPLE_USAGE_ENTRIES"; + case OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION: + return "MIXED_OUTPUT_PROTECTION"; + case OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION: + return "INVALID_ENTITLED_KEY_SESSION"; + case OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING: + return "NEEDS_KEYBOX_PROVISIONING"; + case OEMCrypto_ERROR_UNSUPPORTED_CIPHER: + return "OEMCrypto_ERROR_UNSUPPORTED_CIPHER"; + case OEMCrypto_ERROR_DVR_FORBIDDEN: + return "OEMCrypto_ERROR_DVR_FORBIDDEN"; + case OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE: + return "OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE"; + case OEMCrypto_ERROR_INVALID_KEY: + return "INVALID_KEY"; + // ODK Values. + case ODK_ERROR_CORE_MESSAGE: + return "CORE_MESSAGE"; + case ODK_SET_TIMER: + return "SET_TIMER"; + case ODK_DISABLE_TIMER: + return "DISABLE_TIMER"; + case ODK_TIMER_EXPIRED: + return "TIMER_EXPIRED"; + case ODK_UNSUPPORTED_API: + return "UNSUPPORTED_API"; + case ODK_STALE_RENEWAL: + return "STALE_RENEWAL"; + // OPK Values. + case OPK_ERROR_INCOMPATIBLE_VERSION: + return "INCOMPATIBLE_VERSION"; + case OPK_ERROR_REMOTE_CALL: + return "REMOTE_CALL"; + case OPK_ERROR_NO_PERSISTENT_DATA: + return "NO_PERSISTENT_DATA"; + default: + return "Invalid OEMCrypto error."; + } +} + +} // namespace wvutil diff --git a/util/src/string_format.cpp b/util/src/string_format.cpp new file mode 100644 index 0000000..91cce37 --- /dev/null +++ b/util/src/string_format.cpp @@ -0,0 +1,40 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "string_format.h" + +#include +#include +#include +#include + +#include + +namespace wvutil { + +bool FormatString(std::string* out, const char* fmt, ...) { + if (out == nullptr || fmt == nullptr) return false; + + va_list ap1; + va_start(ap1, fmt); + const int desired_size = vsnprintf(nullptr, 0, fmt, ap1); + va_end(ap1); + + if (desired_size < 0) return false; + const size_t buffer_size = + static_cast(desired_size) + 1; // +1 for null + std::unique_ptr buffer(new char[buffer_size]); + + va_list ap2; + va_start(ap2, fmt); + const int actual_size = vsnprintf(buffer.get(), buffer_size, fmt, ap2); + va_end(ap2); + + if (actual_size != desired_size) return false; + + out->assign(buffer.get(), actual_size); + return true; +} + +} // namespace wvutil diff --git a/util/test/string_format_unittest.cpp b/util/test/string_format_unittest.cpp new file mode 100644 index 0000000..282a43d --- /dev/null +++ b/util/test/string_format_unittest.cpp @@ -0,0 +1,64 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "string_format.h" + +#include +#include + +#include + +namespace wvutil { + +TEST(StringFormatTest, SignedInteger) { + constexpr char kFormat[] = "Version %d"; + constexpr char kResult[] = "Version -123"; + std::string result; + EXPECT_TRUE(FormatString(&result, kFormat, -123)); + EXPECT_EQ(result, kResult); +} + +TEST(StringFormatTest, UnsignedInteger) { + constexpr char kFormat[] = "Version %u"; + constexpr char kResult[] = "Version 27"; + std::string result; + EXPECT_TRUE(FormatString(&result, kFormat, 27)); + EXPECT_EQ(result, kResult); +} + +TEST(StringFormatTest, HexInteger) { + constexpr char kFormat[] = "Version %X"; + constexpr char kResult[] = "Version FF"; + std::string result; + EXPECT_TRUE(FormatString(&result, kFormat, 0xFF)); + EXPECT_EQ(result, kResult); +} + +TEST(StringFormatTest, Strings) { + constexpr char kFormat[] = "Hello, %s."; + constexpr char kResult[] = "Hello, DRM."; + std::string result; + EXPECT_TRUE(FormatString(&result, kFormat, "DRM")); + EXPECT_EQ(result, kResult); +} + +TEST(StringFormatTest, Nothing) { + constexpr char kString[] = "No format fields."; + std::string result; + EXPECT_TRUE(FormatString(&result, kString)); + EXPECT_EQ(result, kString); +} + +TEST(StringFormatTest, NullOutput) { + constexpr char kString[] = "This will never be referenced."; + EXPECT_FALSE(FormatString(nullptr, kString)); +} + +TEST(StringFormatTest, NullFormat) { + std::string result; + EXPECT_FALSE(FormatString(&result, nullptr)); + EXPECT_TRUE(result.empty()); +} + +} // namespace wvutil diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 18331bb..33edd9c 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -2,7 +2,9 @@ // source code may only be used and distributed under the Widevine License // Agreement. // -// Clock - A fake clock just for running tests. +// Clock - A fake clock just for running tests. This is used when running +// OEMCrypto unit tests. It is not used when tests include the CE CDM source +// code because that uses the clock in cdm/test_host.cpp instead. #include