Automated update of OPK code

Included changes:

  - 676ac7be8548d80c420591fc0b4fb9a11723ef34 Backwards compatibility script for CDM v18 and OPK v19 by Vicky Min <vickymin@google.com>
  - 3cd4f71fda91245ac0b61c4c847950952f3021c0 Change BuildInformation ree fields to optional by Matt Feddersen <mattfedd@google.com>
  - a2259e95dea40c27a4be02ad479aec8f1fc84737 Created a DICE CBOR Cert parser/serializer. by Alex Dale <sigquit@google.com>
  - b8f2c364afeb6279e5aee6488d4527e189ac42ff Don't create invalid enum value by John "Juce" Bruce <juce@google.com>
  - b0aed212a3b2dd8f752d8fc43982848c1aa6c152 Created an HLS Key type. by Alex Dale <sigquit@google.com>
  - f8cfc54b41f124ba849596dbe6438b7f271a72b7 Specify C/C++ standard when running clang-tidy on OPK by John "Juce" Bruce <juce@google.com>

GitOrigin-RevId: 676ac7be8548d80c420591fc0b4fb9a11723ef34
This commit is contained in:
Googler
2025-05-13 21:44:08 +00:00
committed by mattfedd
parent a2b9e085e9
commit 5387878a5b
25 changed files with 3139 additions and 937 deletions

View File

@@ -3629,7 +3629,9 @@ uint32_t OEMCrypto_MinorAPIVersion(void);
* defined
*
* While not required, another optional top level struct can be added to the
* build information string to provide information about liboemcrypto.so:
* build information string to provide information about liboemcrypto.so. The
* fields within this struct are not required, but if they are included they
* must match the listed data type:
* - "ree" {
* - "liboemcrypto_ver" [string]: liboemcrypto.so version in string format
* eg "2.15.0+tag". Note that this is separate from the "ta_ver" field

View File

@@ -1,700 +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.
/*********************************************************************
* level3.h
*
* Reference APIs needed to support Widevine's crypto algorithms.
*********************************************************************/
#ifndef LEVEL3_OEMCRYPTO_H_
#define LEVEL3_OEMCRYPTO_H_
#include <stddef.h>
#include <stdint.h>
#include "OEMCryptoCENC.h"
#include "level3_file_system.h"
// clang-format off
#ifdef DYNAMIC_ADAPTER
#define Level3_IsInApp _lcc00
#define Level3_Initialize _lcc01
#define Level3_Terminate _lcc02
#define Level3_InstallKeyboxOrOEMCert _lcc03
#define Level3_GetKeyData _lcc04
#define Level3_IsKeyboxOrOEMCertValid _lcc05
#define Level3_GetRandom _lcc06
#define Level3_GetDeviceID _lcc07
#define Level3_WrapKeyboxOrOEMCert _lcc08
#define Level3_OpenSession _lcc09
#define Level3_CloseSession _lcc10
#define Level3_GenerateSignature _lcc13
#define Level3_GenerateNonce _lcc14
#define Level3_RewrapDeviceRSAKey _lcc18
#define Level3_LoadDeviceRSAKey _lcc19
#define Level3_DeriveKeysFromSessionKey _lcc21
#define Level3_APIVersion _lcc22
#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
#define Level3_GetNumberOfOpenSessions _lcc38
#define Level3_IsAntiRollbackHwPresent _lcc39
#define Level3_QueryKeyControl _lcc41
#define Level3_GetHDCPCapability _lcc44
#define Level3_LoadTestRSAKey _lcc45
#define Level3_SecurityPatchLevel _lcc46
#define Level3_GetProvisioningMethod _lcc49
#define Level3_RewrapDeviceRSAKey30 _lcc51
#define Level3_SupportedCertificates _lcc52
#define Level3_IsSRMUpdateSupported _lcc53
#define Level3_GetCurrentSRMVersion _lcc54
#define Level3_LoadSRM _lcc55
#define Level3_RemoveSRM _lcc57
#define Level3_CreateUsageTableHeader _lcc61
#define Level3_LoadUsageTableHeader _lcc62
#define Level3_CreateNewUsageEntry _lcc63
#define Level3_LoadUsageEntry _lcc64
#define Level3_UpdateUsageEntry _lcc65
#define Level3_ShrinkUsageTableHeader _lcc67
#define Level3_MoveEntry _lcc68
#define Level3_GetAnalogOutputFlags _lcc71
#define Level3_LoadTestKeybox _lcc78
#define Level3_SelectKey _lcc81
#define Level3_LoadKeys _lcc83
#define Level3_SetSandbox _lcc84
#define Level3_ResourceRatingTier _lcc85
#define Level3_SupportsDecryptHash _lcc86
#define Level3_SetDecryptHash_V18 _lcc88
#define Level3_GetHashErrorCode _lcc89
#define Level3_RefreshKeys _lcc91
#define Level3_LoadEntitledContentKeys_V16 _lcc92
#define Level3_CopyBuffer _lcc93
#define Level3_MaximumUsageTableHeaderSize _lcc94
#define Level3_GenerateDerivedKeys _lcc95
#define Level3_PrepAndSignLicenseRequest _lcc96
#define Level3_PrepAndSignRenewalRequest _lcc97
#define Level3_PrepAndSignProvisioningRequest _lcc98
#define Level3_LoadLicense_V18 _lcc99
#define Level3_LoadRenewal _lcc101
#define Level3_LoadProvisioning_V18 _lcc102
#define Level3_LoadOEMPrivateKey _lcc103
#define Level3_GetOEMPublicCertificate _lcc104
#define Level3_DecryptCENC_V17 _lcc105
#define Level3_LoadDRMPrivateKey _lcc107
#define Level3_MinorAPIVersion _lcc108
#define Level3_AllocateSecureBuffer _lcc109
#define Level3_FreeSecureBuffer _lcc110
#define Level3_CreateEntitledKeySession _lcc111
#define Level3_RemoveEntitledKeySession _lcc112
#define Level3_GetBootCertificateChain _lcc116
#define Level3_GenerateCertificateKeyPair _lcc117
#define Level3_InstallOemPrivateKey _lcc118
#define Level3_ReassociateEntitledKeySession _lcc119
#define Level3_LoadCasECMKeys _lcc120
#define Level3_LoadEntitledContentKeys _lcc121 // place holder for v17.
#define Level3_ProductionReady _lcc122
#define Level3_Idle _lcc123
#define Level3_Wake _lcc124
#define Level3_BuildInformation _lcc125
#define Level3_SecurityLevel _lcc126
#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
#define Level3_SetDecryptHash _lcc143
#define Level3_LoadLicense _lcc144
#define Level3_LoadProvisioning _lcc145
#define Level3_LoadProvisioningCast _lcc146
#define Level3_PrepAndSignReleaseRequest _lcc147
#define Level3_GetUsageEntryInfo _lcc148
#define Level3_GetBCCType _lcc149
#define Level3_LoadRelease _lcc150
#define Level3_GetEmbeddedDrmCertificate _lcc151
#define Level3_UseSecondaryKey _lcc152
#define Level3_MarkOfflineSession _lcc153
#define Level3_SetSessionUsage _lcc155
#define Level3_GetBCCSignatureType _lcc156
#define Level3_GetPVRKey _lcc157
#define Level3_LoadPVRKey _lcc158
#define Level3_LoadLicenseData _lcc159
#define Level3_SaveLicenseData _lcc160
#else
#define Level3_Initialize _oecc01
#define Level3_Terminate _oecc02
#define Level3_InstallKeyboxOrOEMCert _oecc03
#define Level3_GetKeyData _oecc04
#define Level3_IsKeyboxOrOEMCertValid _oecc05
#define Level3_GetRandom _oecc06
#define Level3_GetDeviceID _oecc07
#define Level3_WrapKeyboxOrOEMCert _oecc08
#define Level3_OpenSession _oecc09
#define Level3_CloseSession _oecc10
#define Level3_GenerateSignature _oecc13
#define Level3_GenerateNonce _oecc14
#define Level3_RewrapDeviceRSAKey _oecc18
#define Level3_LoadDeviceRSAKey _oecc19
#define Level3_DeriveKeysFromSessionKey _oecc21
#define Level3_APIVersion _oecc22
#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
#define Level3_GetMaxNumberOfSessions _oecc37
#define Level3_GetNumberOfOpenSessions _oecc38
#define Level3_IsAntiRollbackHwPresent _oecc39
#define Level3_QueryKeyControl _oecc41
#define Level3_GetHDCPCapability _oecc44
#define Level3_LoadTestRSAKey _oecc45
#define Level3_SecurityPatchLevel _oecc46
#define Level3_GetProvisioningMethod _oecc49
#define Level3_RewrapDeviceRSAKey30 _oecc51
#define Level3_SupportedCertificates _oecc52
#define Level3_IsSRMUpdateSupported _oecc53
#define Level3_GetCurrentSRMVersion _oecc54
#define Level3_LoadSRM _oecc55
#define Level3_RemoveSRM _oecc57
#define Level3_CreateUsageTableHeader _oecc61
#define Level3_LoadUsageTableHeader _oecc62
#define Level3_CreateNewUsageEntry _oecc63
#define Level3_LoadUsageEntry _oecc64
#define Level3_UpdateUsageEntry _oecc65
#define Level3_DeactivateUsageEntry _oecc66
#define Level3_ShrinkUsageTableHeader _oecc67
#define Level3_MoveEntry _oecc68
#define Level3_GetAnalogOutputFlags _oecc71
#define Level3_LoadTestKeybox _oecc78
#define Level3_SelectKey _oecc81
#define Level3_LoadKeys _oecc83
#define Level3_SetSandbox _oecc84
#define Level3_ResourceRatingTier _oecc85
#define Level3_SupportsDecryptHash _oecc86
#define Level3_SetDecryptHash_V18 _oecc88
#define Level3_GetHashErrorCode _oecc89
#define Level3_RefreshKeys _oecc91
#define Level3_LoadEntitledContentKeys_V16 _oecc92
#define Level3_CopyBuffer _oecc93
#define Level3_MaximumUsageTableHeaderSize _oecc94
#define Level3_GenerateDerivedKeys _oecc95
#define Level3_PrepAndSignLicenseRequest _oecc96
#define Level3_PrepAndSignRenewalRequest _oecc97
#define Level3_PrepAndSignProvisioningRequest _oecc98
#define Level3_LoadLicense_V18 _oecc99
#define Level3_LoadRenewal _oecc101
#define Level3_LoadProvisioning_V18 _oecc102
#define Level3_LoadOEMPrivateKey _oecc103
#define Level3_GetOEMPublicCertificate _oecc104
#define Level3_DecryptCENC_V17 _oecc105
#define Level3_LoadDRMPrivateKey _oecc107
#define Level3_MinorAPIVersion _oecc108
#define Level3_AllocateSecureBuffer _oecc109
#define Level3_FreeSecureBuffer _oecc110
#define Level3_CreateEntitledKeySession _oecc111
#define Level3_RemoveEntitledKeySession _oecc112
#define Level3_GetBootCertificateChain _oecc116
#define Level3_GenerateCertificateKeyPair _oecc117
#define Level3_InstallOemPrivateKey _oecc118
#define Level3_ReassociateEntitledKeySession _oecc119
#define Level3_LoadCasECMKeys _oecc120
#define Level3_LoadEntitledContentKeys _oecc121 // place holder for v17.
#define Level3_ProductionReady _oecc122
#define Level3_Idle _oecc123
#define Level3_Wake _oecc124
#define Level3_BuildInformation _oecc125
#define Level3_SecurityLevel _oecc126
#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
#define Level3_SetDecryptHash _oecc143
#define Level3_LoadLicense _oecc144
#define Level3_LoadProvisioning _oecc145
#define Level3_LoadProvisioningCast _oecc146
#define Level3_PrepAndSignReleaseRequest _oecc147
#define Level3_GetUsageEntryInfo _oecc148
#define Level3_GetBCCType _oecc149
#define Level3_LoadRelease _oecc150
// Internal-only.
#define Level3_GetEmbeddedDrmCertificate _oecc151
#define Level3_UseSecondaryKey _oecc152
#define Level3_MarkOfflineSession _oecc153
#define Level3_SetSessionUsage _oecc155
#define Level3_GetBCCSignatureType _oecc156
#define Level3_GetPVRKey _oecc157
#define Level3_LoadPVRKey _oecc158
#define Level3_LoadLicenseData _oecc159
#define Level3_SaveLicenseData _oecc160
#endif
#define Level3_GetInitializationState _oecl3o01
// clang-format on
extern "C" {
bool Level3_IsInApp();
OEMCryptoResult Level3_Initialize(void);
OEMCryptoResult Level3_Terminate(void);
OEMCryptoResult Level3_OpenSession(OEMCrypto_SESSION* session);
OEMCryptoResult Level3_CloseSession(OEMCrypto_SESSION session);
OEMCryptoResult Level3_GenerateDerivedKeys(OEMCrypto_SESSION session,
const uint8_t* mac_key_context,
size_t mac_key_context_length,
const uint8_t* enc_key_context,
size_t enc_key_context_length);
OEMCryptoResult Level3_GenerateNonce(OEMCrypto_SESSION session,
uint32_t* nonce);
OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length,
uint8_t* key_control_block,
size_t* key_control_block_length);
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,
size_t rotLength);
OEMCryptoResult Level3_IsKeyboxOrOEMCertValid(void);
OEMCryptoResult Level3_WrapKeyboxOrOEMCert(const uint8_t* rot, size_t rotLength,
uint8_t* wrappedRot,
size_t* wrappedRotLength,
const uint8_t* transportKey,
size_t transportKeyLength);
OEMCrypto_ProvisioningMethod Level3_GetProvisioningMethod();
OEMCryptoResult Level3_GetOEMPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length);
OEMCryptoResult Level3_GetDeviceID(uint8_t* deviceID, size_t* idLength);
OEMCryptoResult Level3_GetKeyData(uint8_t* keyData, size_t* keyDataLength);
OEMCryptoResult Level3_GetRandom(OEMCrypto_SharedMemory* randomData,
size_t randomDataLength);
OEMCryptoResult Level3_LoadOEMPrivateKey(OEMCrypto_SESSION session);
OEMCryptoResult Level3_LoadDRMPrivateKey(OEMCrypto_SESSION session,
OEMCrypto_PrivateKeyType key_type,
const uint8_t* wrapped_rsa_key,
size_t wrapped_rsa_key_length);
OEMCryptoResult Level3_LoadProvisioning_V18(
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 Level3_RewrapDeviceRSAKey(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length, const uint32_t* 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 Level3_LoadTestRSAKey();
OEMCryptoResult Level3_GenerateRSASignature(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
OEMCryptoResult Level3_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
const uint8_t* enc_session_key,
size_t enc_session_key_length,
const uint8_t* mac_key_context,
size_t mac_key_context_length,
const uint8_t* enc_key_context,
size_t enc_key_context_length);
uint32_t Level3_APIVersion();
uint32_t Level3_MinorAPIVersion();
uint8_t Level3_SecurityPatchLevel();
OEMCrypto_Security_Level Level3_SecurityLevel();
OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability* current,
OEMCrypto_HDCP_Capability* maximum);
bool Level3_SupportsUsageTable();
bool Level3_IsAntiRollbackHwPresent();
OEMCryptoResult Level3_GetNumberOfOpenSessions(size_t* count);
OEMCryptoResult Level3_GetMaxNumberOfSessions(size_t* maximum);
uint32_t Level3_SupportedCertificates();
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);
OEMCryptoResult Level3_ReportUsage(OEMCrypto_SESSION session,
const uint8_t* pst, size_t pst_length,
uint8_t* buffer, size_t* buffer_length);
OEMCryptoResult Level3_GetUsageEntryInfo(
OEMCrypto_SESSION session, OEMCrypto_UsageEntryStatus* status,
int64_t* seconds_since_license_received,
int64_t* seconds_since_first_decrypt);
bool Level3_IsSRMUpdateSupported();
OEMCryptoResult Level3_GetCurrentSRMVersion(uint16_t* version);
OEMCryptoResult Level3_LoadSRM(const uint8_t* buffer, size_t buffer_length);
OEMCryptoResult Level3_RemoveSRM();
OEMCryptoResult Level3_CreateUsageTableHeader(uint8_t* header_buffer,
size_t* header_buffer_length);
OEMCryptoResult Level3_LoadUsageTableHeader(const uint8_t* buffer,
size_t buffer_length);
OEMCryptoResult Level3_CreateNewUsageEntry(OEMCrypto_SESSION session,
uint32_t* usage_entry_number);
OEMCryptoResult Level3_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t index,
const uint8_t* buffer,
size_t buffer_size);
OEMCryptoResult Level3_UpdateUsageEntry(OEMCrypto_SESSION session,
uint8_t* header_buffer,
size_t* header_buffer_length,
uint8_t* entry_buffer,
size_t* entry_buffer_length);
OEMCryptoResult Level3_ShrinkUsageTableHeader(uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
OEMCryptoResult Level3_MoveEntry(OEMCrypto_SESSION session, uint32_t new_index);
uint32_t Level3_GetAnalogOutputFlags();
OEMCryptoResult Level3_LoadTestKeybox(const uint8_t* buffer, size_t length);
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id, size_t key_id_length,
OEMCryptoCipherMode cipher_mode);
OEMCryptoResult Level3_LoadLicense_V18(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 Level3_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 num_keys, const OEMCrypto_KeyObject* key_array,
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type);
OEMCryptoResult Level3_SetSandbox(const uint8_t* sandbox_id,
size_t sandbox_id_length);
uint32_t Level3_ResourceRatingTier();
uint32_t Level3_SupportsDecryptHash();
OEMCryptoResult Level3_SetDecryptHash(OEMCrypto_SESSION session,
uint32_t frame_number, uint32_t crc32);
OEMCryptoResult Level3_SetDecryptHash_V18(OEMCrypto_SESSION session,
uint32_t frame_number,
const uint8_t* hash,
size_t hash_length);
OEMCryptoResult Level3_GetHashErrorCode(OEMCrypto_SESSION session,
uint32_t* failed_frame_number);
OEMCryptoResult Level3_BuildInformation(char* buffer, size_t* buffer_length);
OEMCryptoResult Level3_LoadRenewal(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 Level3_LoadRelease(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 Level3_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);
OEMCryptoResult Level3_LoadEntitledContentKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t num_keys, const OEMCrypto_EntitledContentKeyObject* key_array);
OEMCryptoResult Level3_CopyBuffer(
OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length,
const OEMCrypto_DestBufferDesc* out_buffer_descriptor,
uint8_t subsample_flags);
OEMCryptoResult Level3_PrepAndSignProvisioningRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length);
OEMCryptoResult Level3_PrepAndSignLicenseRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length);
OEMCryptoResult Level3_PrepAndSignRenewalRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length);
OEMCryptoResult Level3_PrepAndSignReleaseRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_size, uint8_t* signature, size_t* signature_length);
size_t Level3_MaximumUsageTableHeaderSize();
OEMCryptoResult Level3_AllocateSecureBuffer(
OEMCrypto_SESSION session, size_t buffer_size,
OEMCrypto_DestBufferDesc* output_descriptor, int* secure_fd);
OEMCryptoResult Level3_FreeSecureBuffer(
OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor,
int secure_fd);
OEMCryptoResult Level3_CreateEntitledKeySession(OEMCrypto_SESSION oec_session,
OEMCrypto_SESSION* key_session);
OEMCryptoResult Level3_RemoveEntitledKeySession(OEMCrypto_SESSION key_session);
OEMCryptoResult Level3_GetBootCertificateChain(
uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature,
size_t* additional_signature_size);
OEMCryptoResult Level3_GenerateCertificateKeyPair(
OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size,
uint8_t* public_key_signature, size_t* public_key_signature_size,
uint8_t* wrapped_private_key, size_t* wrapped_private_key_size,
OEMCrypto_PrivateKeyType* key_type);
OEMCryptoResult Level3_InstallOemPrivateKey(OEMCrypto_SESSION session,
OEMCrypto_PrivateKeyType key_type,
const uint8_t* wrapped_private_key,
size_t wrapped_private_key_length);
OEMCryptoResult Level3_ReassociateEntitledKeySession(
OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session);
OEMCryptoResult Level3_LoadCasECMKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const OEMCrypto_EntitledContentKeyObject* even_key,
const OEMCrypto_EntitledContentKeyObject* odd_key);
OEMCryptoResult Level3_ProductionReady();
OEMCryptoResult Level3_Idle(OEMCrypto_IdleState state,
uint32_t os_specific_code);
OEMCryptoResult Level3_Wake();
OEMCryptoResult Level3_ReuseUsageEntry(OEMCrypto_SESSION session,
uint32_t usage_entry_number);
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_SetSessionUsage(OEMCrypto_SESSION session,
uint32_t intent, uint32_t mode);
OEMCryptoResult Level3_GetPVRKey(OEMCrypto_SESSION session,
uint8_t* wrapped_pvr_key,
size_t* wrapped_pvr_key_length);
OEMCryptoResult Level3_LoadPVRKey(OEMCrypto_SESSION session,
const uint8_t* wrapped_pvr_key,
size_t wrapped_pvr_key_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);
OEMCryptoResult Level3_LoadLicense(
OEMCrypto_SESSION session, const uint8_t* context, size_t context_length,
const uint8_t* derivation_key, size_t derivation_key_length,
const uint8_t* message, size_t message_length, size_t core_message_length,
const uint8_t* signature, size_t signature_length);
OEMCryptoResult Level3_LoadProvisioning(
OEMCrypto_SESSION session, const uint8_t* provision_request,
size_t provision_request_length, 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 Level3_LoadProvisioningCast(
OEMCrypto_SESSION session, const uint8_t* derivation_key,
size_t derivation_key_length, const uint8_t* provision_request,
size_t provision_request_length, 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 Level3_GetBCCType(OEMCrypto_BCCType* bcc_type);
OEMCryptoResult Level3_GetEmbeddedDrmCertificate(uint8_t* public_cert,
size_t* public_cert_length);
OEMCryptoResult Level3_UseSecondaryKey(OEMCrypto_SESSION session_id,
bool dual_key);
OEMCryptoResult Level3_MarkOfflineSession(OEMCrypto_SESSION session_id);
OEMCryptoResult Level3_LoadLicenseData(OEMCrypto_SESSION session,
const uint8_t* data, size_t data_length);
OEMCryptoResult Level3_SaveLicenseData(OEMCrypto_SESSION session, uint8_t* data,
size_t* data_length);
OEMCryptoResult Level3_GetBCCSignatureType(
OEMCrypto_BCCSignatureType* bcc_signature_type);
// The following are specific to Google's Level 3 implementation and are not
// required.
enum Level3InitializationState {
LEVEL3_INITIALIZATION_SUCCESS = 0,
LEVEL3_INITIALIZATION_UNKNOWN_FAILURE = 1,
LEVEL3_SEED_FAILURE = 2,
LEVEL3_SAVE_DEVICE_KEYS_FAILURE = 3,
LEVEL3_READ_DEVICE_KEYS_FAILURE = 4,
LEVEL3_VERIFY_DEVICE_KEYS_FAILURE = 5,
};
enum Level3RunningMode {
LEVEL3_MODE_HAYSTACK_ONLY = 0,
LEVEL3_MODE_RIKERS_DEFAULT = 1,
LEVEL3_MODE_RIKERS_ONLY = 2,
};
/*
* Level3_GetRunningMode
*
* Description:
* Returns the current mode the Level3 is running in. This shouldn't change
* while the processes is running.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Version:
* This method is new in API version 19.
*/
Level3RunningMode Level3_GetRunningMode(void);
/*
* Level3_GetInitializationState
*
* Description:
* Return any warning or error condition which occurred during
* initialization. On some platforms, this value will be logged and metrics
* will be gathered on production devices. This is an optional feature, and
* OEMCrypto may always return 0, even if Level3_Initialize failed. This
* function may be called whether Level3_Initialize succeeded or not.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Returns:
* LEVEL3_INITIALIZATION_SUCCESS - no warnings or errors during initialization
* LEVEL3_SEED_FAILURE - error in seeding the software RNG
* LEVEL3_SAVE_DEVICE_KEYS_FAILURE - failed to save device keys to file system
* LEVEL3_READ_DEVICE_KEYS_FAILURE - failed to read device keys from file
* system
* LEVEL3_VERIFY_DEVICE_KEYS_FAILURE - failed to verify decrypted device keys
*
* Version:
* This method is new in API version 14.
*/
Level3InitializationState Level3_GetInitializationState(void);
/*
* Level3_OutputErrorLogs
*
* Description:
* Call to output any errors in the Level 3 execution if the Level 3 has
* failed. This method should only be called if the Level 3 has failed in
* an unrecoverable state, and needs to be reinitialized.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Returns:
* N/A
*
* Version:
* This method is new in API version 15.
*/
void Level3_OutputErrorLogs();
} // extern "C"
namespace wvoec3 {
// The following are interfaces needed for Google's Level 3 OEMCrypto
// specifically, which partners are expected to implement.
// Returns a stable, unique identifier for the device. This could be a
// serial number or any other character sequence representing that device.
// The parameter |len| needs to be changed to reflect the length of the
// unique identifier.
const char* getUniqueID(size_t* len);
// Returns a 64-bit unsigned integer to be used as a random seed for RNG.
// If the operation is unsuccessful, this function returns 0.
// We provide a sample implementation under the name generate_entropy_linux.cpp
// which partners should use if they can.
uint64_t generate_entropy();
// Creates and returns an OEMCrypto_Level3FileSystem implementation.
OEMCrypto_Level3FileSystem* createLevel3FileSystem();
// Deletes the pointer retrieved by the function above.
void deleteLevel3FileSystem(OEMCrypto_Level3FileSystem* file_system);
} // namespace wvoec3
#endif // LEVEL3_OEMCRYPTO_H_

View File

@@ -1,32 +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.
/*********************************************************************
* level3_file_system.h
*
* File system for OEMCrypto Level3 file operations.
*********************************************************************/
#ifndef LEVEL3_FILE_SYSTEM_H_
#define LEVEL3_FILE_SYSTEM_H_
#include <stdlib.h>
#include "platform.h"
namespace wvoec3 {
class OEMCrypto_Level3FileSystem {
public:
virtual ~OEMCrypto_Level3FileSystem() {}
virtual ssize_t Read(const char *filename, void *buffer, size_t size) = 0;
virtual ssize_t Write(const char *filename, const void *buffer,
size_t size) = 0;
virtual bool Exists(const char *filename) = 0;
virtual ssize_t FileSize(const char *filename) = 0;
virtual bool Remove(const char *filename) = 0;
};
} // namespace wvoec3
#endif

View File

@@ -36,6 +36,6 @@
#define API_MAJOR_VERSION 20
#define API_MINOR_VERSION 0
#define OPK_PATCH_VERSION 0
#define OPK_BUILD_ID "MAIN"
#define OPK_BUILD_ID "2025-05-30"
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */

View File

@@ -52,6 +52,7 @@ cflags_c += \
cppflags += \
$(cflags) \
-std=c++17 \
$(CPPFLAGS)
# Filter out files and directories in third_party.
@@ -105,7 +106,9 @@ define clang-tidy-rule
.PHONY: clang-tidy-$(1)
clang-tidy-$(1):
@$(cmd-echo-silent) ' CLANG-TIDY $(1)'
${q}clang-tidy $(clang-tidy-flags) $(1) -- $(cflags)
${q}clang-tidy $(clang-tidy-flags) $(1) -- $(cflags) \
$(if $(filter .c,$(suffix $(1))),-std=c11 -D_POSIX_C_SOURCE=200809L) \
$(if $(filter .cpp,$(suffix $(1))),-std=c++17)
endef
define clang-tidy-rule-cpp

View File

@@ -8,7 +8,7 @@
#define OPK_CONFIG_H_
#ifndef OPK_CONFIG_SECURITY_LEVEL
# define OPK_CONFIG_SECURITY_LEVEL OEMCrypto_Level3
# define OPK_CONFIG_SECURITY_LEVEL OEMCrypto_Level1
#endif
#ifndef OPK_CONFIG_RESOURCE_RATING_TIER

View File

@@ -106,7 +106,9 @@ define clang-tidy-rule
.PHONY: clang-tidy-$(1)
clang-tidy-$(1):
@$(cmd-echo-silent) ' CLANG-TIDY $(1)'
${q}clang-tidy $(clang-tidy-flags) $(1) -- $(cflags)
${q}clang-tidy $(clang-tidy-flags) $(1) -- $(cflags) \
$(if $(filter .c,$(suffix $(1))),-std=c11 -D_POSIX_C_SOURCE=200809L) \
$(if $(filter .cpp,$(suffix $(1))),-std=c++17)
endef
define clang-tidy-rule-cpp

View File

@@ -28,6 +28,8 @@ clang-tidy-flags = \
clang-tidy-cflags = \
-m$(ARCH) \
$(if $(filter .c,$(suffix $(1))),-std=c11 -D_POSIX_C_SOURCE=200809L) \
$(if $(filter .cpp,$(suffix $(1))),-std=c++17) \
$(comp-cppflags-$(call oname,$(1)))
# Define a rule template to run clang-tidy with a single source file.

View File

@@ -26,6 +26,8 @@ clang-tidy-flags := \
clang-tidy-cflags := \
$(MODULE_CFLAGS) \
$(if $(filter .c,$(suffix $(1))),-std=c11 -D_POSIX_C_SOURCE=200809L) \
$(if $(filter .cpp,$(suffix $(1))),-std=c++17) \
$(addprefix -D,$(MODULE_DEFINES) TRUSTY_USERSPACE) \
$(addprefix -I,\
$(MODULE_INCLUDES) \
@@ -37,7 +39,7 @@ clang-tidy-cflags := \
define clang-tidy-rule
.PHONY: clang-tidy-$(1)
clang-tidy-$(1): clang-tidy-flags := $(clang-tidy-flags)
clang-tidy-$(1): clang-tidy-cflags := $(clang-tidy-cflags)
clang-tidy-$(1): clang-tidy-cflags := $(call clang-tidy-cflags,$(1))
clang-tidy-$(1):
@echo running clang-tidy: $(1)
$(NOECHO)clang-tidy $(clang-tidy-flags) $(1) -- $(clang-tidy-cflags)

View File

@@ -1,5 +0,0 @@
# Android Format Style
edition = "2021"
use_small_heuristics = "Max"
newline_style = "Unix"

View File

@@ -0,0 +1,75 @@
# Copyright (C) 2024 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
WV_TA_TOP_LEVEL := $(LOCAL_DIR)/../../../../
SHARED_DIR := $(WV_TA_TOP_LEVEL)/shared
IMPL_DIR := $(WV_TA_TOP_LEVEL)/interface_impls
CDM_DIR := trusty/vendor/widevine/cdm
APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta
SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization
ODK_DIR := $(CDM_DIR)/oemcrypto/odk
ifndef WIDEVINE_PROVISION_METHOD
$(error WIDEVINE_PROVISION_METHOD is not set. \
Please set it in the [target_name]-inc.mk file of your project)
endif
MODULE_DEFINES += \
WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \
# Default value if WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE is not set by *-inc.mk.
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE ?= 0
MODULE_DEFINES += \
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE=$(WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE)
MODULE_DEFINES += \
OPK_CONFIG_SOC_VENDOR_NAME=Google \
OPK_CONFIG_SOC_MODEL_NAME=$(PLATFORM) \
OPK_CONFIG_TEE_OS_NAME=Trusty \
OPK_CONFIG_TEE_OS_VERSION=0.0 \
OPK_CONFIG_DEVICE_FORM_FACTOR=phone+tablet \
OPK_CONFIG_IMPLEMENTER_NAME=Widevine \
WTPI_BUILD_INFO=TRUSTY \
# Widevine vendor code assumes trusty defines __linux__. We need to get this
# fixed upstream. TODO(b/232255239)
MODULE_CFLAGS += -D__linux__
MODULE_SRCS += \
$(APP_DIR)/wtpi_reference/wtpi_decrypt_sample.c \
MODULE_INCLUDES += \
$(LOCAL_DIR)/include \
$(SHARED_DIR)/include \
MODULE_INCLUDES += \
$(CDM_DIR)/oemcrypto/include \
$(ODK_DIR)/include \
$(CDM_DIR)/oemcrypto/odk/src \
$(IMPL_DIR) \
$(APP_DIR) \
$(WV_TA_TOP_LEVEL)/include \
$(APP_DIR)/wtpi \
$(APP_DIR)/wtpi_reference \
MODULE_LIBRARY_DEPS += \
trusty/user/base/lib/libc-trusty \
include make/library.mk

View File

@@ -0,0 +1,71 @@
# Copyright (C) 2024 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
TOP_LEVEL := $(LOCAL_DIR)/../../../../
SHARED_DIR := $(TOP_LEVEL)/shared
IMPL_DIR := $(TOP_LEVEL)/interface_impls
CDM_DIR := trusty/vendor/widevine/cdm
APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta
SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization
ODK_DIR := $(CDM_DIR)/oemcrypto/odk
ifndef WIDEVINE_PROVISION_METHOD
$(error WIDEVINE_PROVISION_METHOD is not set. \
Please set it in the [target_name]-inc.mk file of your project)
endif
MODULE_DEFINES += \
WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \
# Default value if WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE is not set by *-inc.mk.
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE ?= 0
MODULE_DEFINES += \
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE=$(WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE)
MODULE_DEFINES += \
OPK_CONFIG_SOC_VENDOR_NAME=Google \
OPK_CONFIG_SOC_MODEL_NAME=$(PLATFORM) \
OPK_CONFIG_TEE_OS_NAME=Trusty \
OPK_CONFIG_TEE_OS_VERSION=0.0 \
OPK_CONFIG_DEVICE_FORM_FACTOR=phone+tablet \
OPK_CONFIG_IMPLEMENTER_NAME=Widevine \
WTPI_BUILD_INFO=TRUSTY \
MODULE_SRCS += \
$(IMPL_DIR)/derive_key.c \
MODULE_INCLUDES += \
$(LOCAL_DIR)/include \
$(SHARED_DIR)/include \
MODULE_INCLUDES += \
$(CDM_DIR)/oemcrypto/include \
$(ODK_DIR)/include \
$(CDM_DIR)/oemcrypto/odk/src \
$(IMPL_DIR) \
$(APP_DIR) \
$(TOP_LEVEL)/include \
$(APP_DIR)/wtpi \
$(APP_DIR)/wtpi_reference \
MODULE_LIBRARY_DEPS += \
trusty/user/base/lib/hwkey \
include make/library.mk

View File

@@ -0,0 +1,95 @@
# Copyright (C) 2024 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
WV_TA_TOP_LEVEL := $(LOCAL_DIR)/../../../../
SHARED_DIR := $(WV_TA_TOP_LEVEL)/shared
IMPL_DIR := $(WV_TA_TOP_LEVEL)/interface_impls
CDM_DIR := trusty/vendor/widevine/cdm
APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta
SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization
ODK_DIR := $(CDM_DIR)/oemcrypto/odk
ifndef WIDEVINE_PROVISION_METHOD
$(error WIDEVINE_PROVISION_METHOD is not set. \
Please set it in the [target_name]-inc.mk file of your project)
endif
# 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
# TODO: remove when unused variable in dump_ssl_error() is fixed
MODULE_CFLAGS += -Wno-error=unused-but-set-variable
MODULE_DEFINES += \
WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \
# Default value if WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE is not set by *-inc.mk.
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE ?= 0
MODULE_DEFINES += \
WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE=$(WIDEVINE_PROVISION_BCC_SIGNATURE_TYPE)
MODULE_DEFINES += \
OPK_CONFIG_SOC_VENDOR_NAME=Google \
OPK_CONFIG_SOC_MODEL_NAME=$(PLATFORM) \
OPK_CONFIG_TEE_OS_NAME=Trusty \
OPK_CONFIG_TEE_OS_VERSION=0.0 \
OPK_CONFIG_DEVICE_FORM_FACTOR=phone+tablet \
OPK_CONFIG_IMPLEMENTER_NAME=Widevine \
WTPI_BUILD_INFO=TRUSTY \
# Widevine vendor code assumes trusty defines __linux__. We need to get this
# fixed upstream. TODO(b/232255239)
MODULE_CFLAGS += -D__linux__
# The base Trusty app.
MODULE_SRCS += \
$(IMPL_DIR)/wtpi_persistent_storage_layer1.c \
$(IMPL_DIR)/wtpi_initialize_terminate.c \
$(IMPL_DIR)/wtpi_root_of_trust_layer2.c \
$(WV_TA_TOP_LEVEL)/tee_context.c \
MODULE_INCLUDES += \
$(WV_TA_TOP_LEVEL)/include \
$(CDM_DIR)/oemcrypto/include \
$(ODK_DIR)/include \
$(SERIALIZATION_DIR)/common \
$(SERIALIZATION_DIR)/common/include \
$(CDM_DIR)/oemcrypto/odk/src \
$(SERIALIZATION_DIR)/os_interfaces \
$(IMPL_DIR) \
MODULE_INCLUDES += \
$(APP_DIR) \
$(APP_DIR)/wtpi \
$(APP_DIR)/wtpi_reference \
MODULE_LIBRARY_DEPS += \
trusty/user/base/lib/libc-trusty \
trusty/user/base/lib/storage \
include make/library.mk

View File

@@ -450,11 +450,3 @@ OEMCryptoResult _oecc157(OEMCrypto_SESSION session, uint8_t* wrapped_pvr_key,
OEMCryptoResult _oecc158(OEMCrypto_SESSION session,
const uint8_t* wrapped_pvr_key,
size_t wrapped_pvr_key_length);
// OEMCrypto_LoadLicenseData defined in v20.0
OEMCryptoResult _oecc159(OEMCrypto_SESSION session, const uint8_t* data,
size_t data_length);
// OEMCrypto_SaveLicenseData defined in v20.0
OEMCryptoResult _oecc160(OEMCrypto_SESSION session, uint8_t* data,
size_t* data_length);

View File

@@ -693,7 +693,7 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
// Whether this was built with FACTORY_MODE_ONLY defined
{"is_factory_mode", JSMN_PRIMITIVE},
// ... provide information about liboemcrypto.so
// Special case, see kOptionalReeFields for details.
// Special case, see kReeOptionalFields for details.
{kSpecialCaseReeKey, JSMN_OBJECT},
// Technically required, but several implementations
// do not implement this fields.
@@ -791,7 +791,7 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
// The optional field "ree", if present, must follow the required
// format.
const std::map<std::string, jsmntype_t> kReeRequiredFields = {
const std::map<std::string, jsmntype_t> kReeOptionalFields = {
// liboemcrypto.so version in string format eg "2.15.0+tag"
{"liboemcrypto_ver", JSMN_STRING},
// git hash of code that compiled liboemcrypto.so
@@ -799,7 +799,6 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
// ISO 8601 timestamp for when liboemcrypto.so was built
{"build_timestamp", JSMN_STRING}};
found_required_fields.clear();
for (int32_t i = 0; (i + 1) < static_cast<int32_t>(ree_tokens.size());
i += 2) {
const jsmntok_t& key_token = ree_tokens[i];
@@ -809,11 +808,10 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
const std::string key =
build_info.substr(key_token.start, key_token.end - key_token.start);
if (kReeRequiredFields.find(key) != kReeRequiredFields.end()) {
ASSERT_EQ(value_token.type, kReeRequiredFields.at(key))
if (kReeOptionalFields.find(key) != kReeOptionalFields.end()) {
ASSERT_EQ(value_token.type, kReeOptionalFields.at(key))
<< "Unexpected optional REE field type: ree_field = " << key
<< ", build_info = " << build_info;
found_required_fields.insert(key);
RecordWvProperty(kReeBuildInfoRecordPrefix + key,
build_info.substr(value_token.start,
value_token.end - value_token.start));
@@ -823,25 +821,6 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
i += JsmnAncestorCount(ree_tokens, i + 1);
}
// Step 4b: Ensure all required fields of the "ree" object were found.
if (found_required_fields.size() == kReeRequiredFields.size()) return;
// Generate a list of all the missing REE fields.
std::string missing_ree_fields;
for (const auto& required_field : kReeRequiredFields) {
if (found_required_fields.find(required_field.first) !=
found_required_fields.end())
continue;
if (!missing_ree_fields.empty()) {
missing_ree_fields.append(", ");
}
missing_ree_fields.push_back('"');
missing_ree_fields.append(required_field.first);
missing_ree_fields.push_back('"');
}
FAIL() << "REE info JSON object does not contain all required keys; "
<< "missing_ree_fields = [" << missing_ree_fields
<< "], build_info = " << build_info;
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {

View File

@@ -39,6 +39,7 @@
'sources': [
'<(wvcrypto_dir)/src/cmac.cpp',
'<(wvcrypto_dir)/src/cose_utils.cpp',
'<(wvcrypto_dir)/src/dice_cert_utils.cpp',
'<(wvcrypto_dir)/src/hmac.cpp',
'<(wvcrypto_dir)/src/oemcrypto_cose_key.cpp',
'<(wvcrypto_dir)/src/oemcrypto_drm_key.cpp',

View File

@@ -0,0 +1,346 @@
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#ifndef WVOEC_UTIL_DICE_CERT_UTILS_H_
#define WVOEC_UTIL_DICE_CERT_UTILS_H_
#include <inttypes.h>
#include <optional>
#include <string>
#include <vector>
#include "wv_class_utils.h"
namespace wvoec {
namespace util {
// ==== DICE UDS/CDI CBOR Certificates ====
// DICE UDS/CDI CBOR Certificates are based on CBOR Web Token (CWT).
// For CWT, RFC 8392
// Token issuer ("iss") => tstr
// Identifies the issuer of the CWT/Cert.
// For DICE, this is a lower-hex encoded UDS_ID/CDI_ID.
constexpr int64_t kDiceIssuerLabel = 1;
// Token subject ("sub") => tstr
// Identifies the subject of the CWT/Cert.
// For DICE, this is a lower-hex encoded CDI_ID.
constexpr int64_t kDiceSubjectLabel = 2;
// Token audience ("aud") => tstr
// Identifies the audience of the CWT/Cert.
// Not used for DICE.
constexpr int64_t kDiceAudienceLabel = 3;
// Expiration time ("exp") => int / float (CWT NumericDate)
// Time of expiry of certificate.
// For DICE, this is only available if a reliable time source is available.
constexpr int64_t kDiceExpirationTimeLabel = 4;
// Not before time ("nbf") => int / float (CWT NumericDate)
// Time after which the certificate may be used.
// For DICE, this is only available if a reliable time source is available.
constexpr int64_t kDiceNotBeforeLabel = 5;
// Issued at time ("iat") => int / float (CWT NumericDate)
// Time which the certificate was issued.
// For DICE, this is only available if a reliable time source is available.
constexpr int64_t kDiceIssuedAtLabel = 6;
// CWT ID ("cti") => bstr
// Used to identify the token claim.
// Not used for DICE.
constexpr int64_t kDiceCwtIdLabel = 7;
// From Open Profile for DICE
// Code hash ("codeHash") => bstr
// Exact code input value used to compute CDI values.
// For Android/Widevine DICE, this is unpadded
// For Open DICE, this is always 64 bytes.
constexpr int64_t kDiceCodeHashLabel = -4670545;
// Code Descriptor ("codeDescriptor") => bstr
// Contains additional information about the code input value.
// Exact format is implementation specific.
constexpr int64_t kDiceCodeDescriptorLabel = -4670546;
// Config Input Hash ("configurationHash") => bstr
// If the configation input is hashed, this is that hash; if
// config input is not hashed, than this field is omitted.
// For Android/Widevine DICE, this is unpadded and required.
// For Open DICE, this is always 64 bytes.
constexpr int64_t kDiceConfigHashLabel = -4670547;
// Configuration Descriptor ("configurationDescriptor") => bstr
// If configuration input is hashed, this field contains the original
// configuration data that was hash, if not hash, this field contains
// the exact 64-byte configuration input value used to compute
// the CDI values.
// For Android/Widevine DICE, this is a CBOR encoded map.
constexpr int64_t kDiceConfigDescriptorLabel = -4670548;
// Authority Input Hash ("authorityHash") => bstr
// Exact authority input used to compute the CDI values.
// For Android/Widevine DICE, this is unpadded and required.
// For Open DICE, this is always 64 bytes.
constexpr int64_t kDiceAuthorityHashLabel = -4670549;
// Authority Descriptor ("authorityDescriptor") => bstr
// If configuration input is hashed, this field contains the original
// configuration data that was hash, if not hash, this field is
// omitted.
constexpr int64_t kDiceAuthorityDescriptorLabel = -4670550;
// DICE Mode ("mode") => bstr .size 1
// DICE config mode. Encoded as a bstr of size 1; which represents
// one of the enumerated DICE modes (0-3).
constexpr int64_t kDiceModeLabel = -4670551;
// Subject Public Key ("subjectPublicKey") => bstr
// Contains the public key of this certificate's subject. Should
// be a CBOR encoded COSE_Key (public key only).
constexpr int64_t kDiceSubjectPublicKeyLabel = -4670552;
// Key usage ("keyUsage") => bstr
// Contains the key usage of the subject public key. Contains
// a little-endian encoded integer representing an X.509 KeyUsage
// bit field. Should only be set to "keyCertSign" bit.
constexpr int64_t kDiceKeyUsageLabel = -4670553;
// Profile Name ("profileName") => tstr
// This is the name of the DICE profile that defines the contents
// of this certificate.
// For Android DICE, required and format "android.<Android Version>"
// For Widevine DICE, required and format "widevine.<OEMCrypto major version>"
// For Open DICE, optional.
constexpr int64_t kDiceProfileNameLabel = -4670554;
constexpr uint8_t kDiceModeNotConfigured = 0;
constexpr uint8_t kDiceModeNormal = 1;
constexpr uint8_t kDiceModeDebug = 2;
constexpr uint8_t kDiceModeRecovery = 3;
// Decoded form of the X.509 key usage bits.
// DICE only recognizes "keyCertSign".
// See RFC 5280 section 4.2.1.3 for details of defined bits.
using DiceKeyUsageFlags = uint16_t;
// Subject public key is used for certificate signature
// verification.
constexpr DiceKeyUsageFlags kKeyCertSignBit = (1 << 5);
class DiceCertData {
public:
// Decodes the bstr format "mode" field into a raw DICE mode byte.
// Returns:
// - Raw DICE mode byte on success
// - nullopt if |mode_bstr| does not represent a valid bstr encoded
// mode.
static std::optional<uint8_t> DecodeModeBytes(
const std::vector<uint8_t>& mode_bstr);
// Encodes the raw DICE mode into the bstr format of "mode".
static std::vector<uint8_t> EncodeModeBytes(uint8_t mode) {
return std::vector<uint8_t>(1, mode);
}
// Decodes the bstr format "keyUsage" field into a raw X.509
// key usage bit field.
// Returns:
// - Raw X.506 bit field.
// - nullopt if |key_usage_bstr| cannot represent a valid bstr
// encoded key usage bit field.
static std::optional<DiceKeyUsageFlags> DecodeKeyUsageBytes(
const std::vector<uint8_t>& key_usage_bstr);
static std::vector<uint8_t> EncodeKeyUsageBytes(
const DiceKeyUsageFlags& key_usage);
DiceCertData() = default;
WVCDM_DEFAULT_COPY_AND_MOVE(DiceCertData);
// == CWT Fields ==
const std::optional<std::string>& issuer() const { return issuer_; }
bool has_issuer() const { return issuer_.has_value(); }
void set_issuer(const std::string& issuer) { issuer_ = issuer; }
void clear_issuer() { issuer_.reset(); }
const std::optional<std::string>& subject() const { return subject_; }
bool has_subject() const { return subject_.has_value(); }
void set_subject(const std::string& subject) { subject_ = subject; }
void clear_subject() { subject_.reset(); }
const std::optional<std::string>& audience() const { return audience_; }
bool has_audience() const { return audience_.has_value(); }
void set_audience(const std::string& audience) { audience_ = audience; }
void clear_audience() { audience_.reset(); }
const std::optional<int64_t>& expiration_time() const {
return expiration_time_;
}
bool has_expiration_time() const { return expiration_time_.has_value(); }
void set_expiration_time(int64_t time) { expiration_time_ = time; }
void clear_expiration_time() { expiration_time_.reset(); }
const std::optional<int64_t>& not_before_time() const {
return not_before_time_;
}
bool has_not_before_time() const { return not_before_time_.has_value(); }
void set_not_before_time(int64_t time) { not_before_time_ = time; }
void clear_not_before_time() { not_before_time_.reset(); }
const std::optional<int64_t>& issued_time() const { return issued_time_; }
bool has_issued_time() const { return issued_time_.has_value(); }
void set_issued_time(int64_t time) { issued_time_ = time; }
void clear_issued_time() { issued_time_.reset(); }
const std::optional<std::vector<uint8_t>>& cwt_id() const { return cwt_id_; }
bool has_cwt_id() const { return cwt_id_.has_value(); }
void set_cwt_id(const std::vector<uint8_t>& id) { cwt_id_ = id; }
void clear_cwt_id() { cwt_id_.reset(); }
// == DICE CDI Fields ==
const std::optional<std::vector<uint8_t>>& code_hash() const {
return code_hash_;
}
bool has_code_hash() const { return code_hash_.has_value(); }
void set_code_hash(const std::vector<uint8_t>& hash) { code_hash_ = hash; }
void clear_code_hash() { code_hash_.reset(); }
const std::optional<std::vector<uint8_t>>& code_descriptor() const {
return code_descriptor_;
}
bool has_code_descriptor() const { return code_descriptor_.has_value(); }
void set_code_descriptor(const std::vector<uint8_t>& descriptor) {
code_descriptor_ = descriptor;
}
void clear_code_descriptor() { code_descriptor_.reset(); }
const std::optional<std::vector<uint8_t>>& config_hash() const {
return config_hash_;
}
bool has_config_hash() const { return config_hash_.has_value(); }
void set_config_hash(const std::vector<uint8_t>& hash) {
config_hash_ = hash;
}
void clear_config_hash() { config_hash_.reset(); }
const std::optional<std::vector<uint8_t>>& config_descriptor() const {
return config_descriptor_;
}
bool has_config_descriptor() const { return config_descriptor_.has_value(); }
void set_config_descriptor(const std::vector<uint8_t>& descriptor) {
config_descriptor_ = descriptor;
}
void clear_config_descriptor() { config_descriptor_.reset(); }
const std::optional<std::vector<uint8_t>>& authority_hash() const {
return authority_hash_;
}
bool has_authority_hash() const { return authority_hash_.has_value(); }
void set_authority_hash(const std::vector<uint8_t>& hash) {
authority_hash_ = hash;
}
void clear_authority_hash() { authority_hash_.reset(); }
const std::optional<std::vector<uint8_t>>& authority_descriptor() const {
return authority_descriptor_;
}
bool has_authority_descriptor() const {
return authority_descriptor_.has_value();
}
void set_authority_descriptor(const std::vector<uint8_t>& descriptor) {
authority_descriptor_ = descriptor;
}
void clear_authority_descriptor() { authority_descriptor_.reset(); }
const std::optional<uint8_t>& mode() const { return mode_; }
bool has_mode() const { return mode_.has_value(); }
void set_mode(uint8_t mode) { mode_ = mode; }
void clear_mode() { mode_.reset(); }
const std::optional<std::vector<uint8_t>>& subject_public_key() const {
return subject_public_key_;
}
bool has_subject_public_key() const {
return subject_public_key_.has_value();
}
void set_subject_public_key(const std::vector<uint8_t>& key) {
subject_public_key_ = key;
}
void clear_subject_public_key() { subject_public_key_.reset(); }
const std::optional<DiceKeyUsageFlags>& key_usage() const {
return key_usage_;
}
bool has_key_usage() const { return key_usage_.has_value(); }
void set_key_usage(DiceKeyUsageFlags key_usage) { key_usage_ = key_usage; }
void clear_key_usage() { key_usage_.reset(); }
const std::optional<std::string>& profile_name() const {
return profile_name_;
}
bool has_profile_name() const { return profile_name_.has_value(); }
void set_profile_name(const std::string& name) { profile_name_ = name; }
void clear_profile_name() { profile_name_.reset(); }
void Clear() {
// CWT fields.
clear_issuer();
clear_subject();
clear_audience();
clear_expiration_time();
clear_not_before_time();
clear_issued_time();
clear_cwt_id();
// DICE CDI fields.
clear_code_hash();
clear_code_descriptor();
clear_config_hash();
clear_config_descriptor();
clear_authority_hash();
clear_authority_descriptor();
clear_mode();
clear_subject_public_key();
clear_key_usage();
clear_profile_name();
}
// Parses the CBOR CWT/DICE Cert.
// Input should be a CBOR serializes map.
// Limited validation:
// - All defined fields are treated as optional (even
// if standard says they are required)
// - Defined fields, if present, must be the expected type.
// - "mode", if present must be a bstr containing a single byte,
// raw value will be stored, even if out of range of defined
// modes.
// - "keyUsage", if present, must decode as a little-endian
// integer that can fit into a uint16_t
// - Additional fields are dropped
// Returns true if successfully parsed, false otherwise.
bool ParseCbor(const uint8_t* buffer, size_t buffer_size);
bool ParseCbor(const std::vector<uint8_t>& buffer) {
return ParseCbor(buffer.data(), buffer.size());
}
// Serializes the DICE Cert.
// - Any set field will be encoded as the type defined.
// - "mode" will be encoded as a bstr containing a single byte
// - "keyUsage" will be encoded as a little-endian integer,
// using the 1 or 2 bytes (0 is encoded as 1 byte).
std::vector<uint8_t> SerializeCbor() const;
private:
// CWT fields.
std::optional<std::string> issuer_ = std::nullopt;
std::optional<std::string> subject_ = std::nullopt;
std::optional<std::string> audience_ = std::nullopt;
std::optional<int64_t> expiration_time_ = std::nullopt;
std::optional<int64_t> not_before_time_ = std::nullopt;
std::optional<int64_t> issued_time_ = std::nullopt;
std::optional<std::vector<uint8_t>> cwt_id_ = std::nullopt;
// Open DICE fields.
std::optional<std::vector<uint8_t>> code_hash_ = std::nullopt;
std::optional<std::vector<uint8_t>> code_descriptor_ = std::nullopt;
std::optional<std::vector<uint8_t>> config_hash_ = std::nullopt;
std::optional<std::vector<uint8_t>> config_descriptor_ = std::nullopt;
std::optional<std::vector<uint8_t>> authority_hash_ = std::nullopt;
std::optional<std::vector<uint8_t>> authority_descriptor_ = std::nullopt;
std::optional<uint8_t> mode_ = std::nullopt;
std::optional<std::vector<uint8_t>> subject_public_key_ = std::nullopt;
std::optional<DiceKeyUsageFlags> key_usage_ = std::nullopt;
std::optional<std::string> profile_name_ = std::nullopt;
}; // class DiceCertData
} // namespace util
} // namespace wvoec
#endif // WVOEC_UTIL_DICE_CERT_UTILS_H_

View File

@@ -19,6 +19,7 @@
'<(oemcrypto_dir)/util/test/cmac_unittest.cpp',
'<(oemcrypto_dir)/util/test/cose_utils_unittest.cpp',
'<(oemcrypto_dir)/util/test/device_info_validator_unittest.cpp',
'<(oemcrypto_dir)/util/test/dice_cert_utils_unittest.cpp',
'<(oemcrypto_dir)/util/test/hmac_unittest.cpp',
'<(oemcrypto_dir)/util/test/oem_cert_test.cpp',
'<(oemcrypto_dir)/util/test/oemcrypto_cose_key_unittest.cpp',

View File

@@ -0,0 +1,421 @@
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "dice_cert_utils.h"
#include <inttypes.h>
#include <optional>
#include <string>
#include <vector>
#include <cppbor.h>
#include <cppbor_parse.h>
#include "log.h"
#include "string_conversions.h"
namespace wvoec {
namespace util {
namespace {
// == cppbor Utils ==
bool IsItemMapType(const cppbor::Item& item) {
return item.type() == cppbor::MAP;
}
bool IsItemIntType(const cppbor::Item& item) {
return item.type() == cppbor::UINT || item.type() == cppbor::NINT;
}
bool IsItemBstrType(const cppbor::Item& item) {
return item.type() == cppbor::BSTR;
}
bool IsItemTstrType(const cppbor::Item& item) {
return item.type() == cppbor::TSTR;
}
const char* SimpleItemTypeToString(const cppbor::Simple& item) {
switch (item.simpleType()) {
case cppbor::BOOLEAN:
return "bool";
case cppbor::NULL_T:
return "nil";
// case cppbor::FLOAT:
// case cppbor::DOUBLE:
// return "float";
// CDM's version of cppbor is out of date and does not support
// the simple types FLOAT and DOUBLE; however, Android's version does.
// Adding "default" to prevent compilation errors if/when CDM's cppbor
// is updated.
default:
break;
}
return "unknownSimple";
}
const char* ItemTypeToString(const cppbor::Item& item) {
switch (item.type()) {
case cppbor::UINT:
case cppbor::NINT:
return "int";
case cppbor::BSTR:
return "bstr";
case cppbor::TSTR:
return "tstr";
case cppbor::ARRAY:
return "array";
case cppbor::MAP:
return "map";
case cppbor::SEMANTIC:
// Could be other things, but most common is tag.
return "tag";
case cppbor::SIMPLE:
return SimpleItemTypeToString(*item.asSimple());
}
return "unknown";
}
} // namespace
// static
std::optional<uint8_t> DiceCertData::DecodeModeBytes(
const std::vector<uint8_t>& mode_bstr) {
if (mode_bstr.size() != 1) {
LOGE("Invalid length of mode bstr: length = %zu, expected = 1",
mode_bstr.size());
return std::nullopt;
}
return mode_bstr.front();
}
// static
std::optional<DiceKeyUsageFlags> DiceCertData::DecodeKeyUsageBytes(
const std::vector<uint8_t>& key_usage_bstr) {
if (key_usage_bstr.empty() || key_usage_bstr.size() > 2) {
LOGE("Invalid length of key usage bstr: length = %zu, min = 1, max = 2",
key_usage_bstr.size());
return std::nullopt;
}
// Decode as little-endian (reverse iterator).
DiceKeyUsageFlags key_usage = 0;
for (auto it = key_usage_bstr.rbegin(); it != key_usage_bstr.rend(); ++it) {
key_usage = (key_usage << 8) | static_cast<DiceKeyUsageFlags>(*it);
}
return key_usage;
}
// static
std::vector<uint8_t> DiceCertData::EncodeKeyUsageBytes(
const DiceKeyUsageFlags& key_usage) {
if (key_usage == 0) {
// Special case, always encode at least 1 byte.
return std::vector<uint8_t>(1, 0);
}
std::vector<uint8_t> key_usage_bstr;
key_usage_bstr.reserve(sizeof(DiceKeyUsageFlags));
DiceKeyUsageFlags temp = key_usage;
// Encode as little-endian.
// Note: Must be encoded using the fewest number of bytes
// necessary with a minimum of 1.
while (temp > 0) {
key_usage_bstr.push_back(static_cast<uint8_t>(temp & 0xff));
temp >>= 8;
}
return key_usage_bstr;
}
bool DiceCertData::ParseCbor(const uint8_t* buffer, size_t buffer_size) {
if (buffer == nullptr) {
LOGE("Input |buffer| is null");
return false;
}
if (buffer_size == 0) {
LOGE("Input |buffer| is empty");
return false;
}
Clear(); // Clear existing data.
const auto [cert_item, end_pos, error_message] =
cppbor::parse(buffer, buffer_size);
if (!cert_item) {
LOGE("Failed to parse CBOR DICE Cert: %s", error_message.c_str());
return false;
}
if (!IsItemMapType(*cert_item)) {
LOGE("CBOR item is not a map: type = %s", ItemTypeToString(*cert_item));
return false;
}
const cppbor::Map* cert_map = cert_item->asMap();
// Issuer "iss" => tstr
const auto& issuer_item = cert_map->get(kDiceIssuerLabel);
if (issuer_item) {
if (!IsItemTstrType(*issuer_item)) {
LOGE("Expected 'iss' field to be a tstr: type = %s",
ItemTypeToString(*issuer_item));
return false;
}
issuer_ = issuer_item->asTstr()->value();
}
// Subject "sub" => tstr
const auto& subject_item = cert_map->get(kDiceSubjectLabel);
if (subject_item) {
if (!IsItemTstrType(*subject_item)) {
LOGE("Expected 'sub' field to be a tstr: type = %s",
ItemTypeToString(*subject_item));
return false;
}
subject_ = subject_item->asTstr()->value();
}
// Audience "aud" => tstr
const auto& audience_item = cert_map->get(kDiceAudienceLabel);
if (audience_item) {
if (!IsItemTstrType(*audience_item)) {
LOGE("Expected 'aud' field to be a tstr: type = %s",
ItemTypeToString(*audience_item));
return false;
}
audience_ = audience_item->asTstr()->value();
}
// Note: Version of cppbor does not support float/double.
// Expiration time "exp" -> int / float
const auto& expiration_time_item = cert_map->get(kDiceExpirationTimeLabel);
if (expiration_time_item) {
if (!IsItemIntType(*expiration_time_item)) {
LOGE("Expected 'exp' field to be a int: type = %s",
ItemTypeToString(*expiration_time_item));
return false;
}
expiration_time_ = expiration_time_item->asInt()->value();
}
// Not before time "nbf" -> int / float
const auto& not_before_time_item = cert_map->get(kDiceNotBeforeLabel);
if (not_before_time_item) {
if (!IsItemIntType(*not_before_time_item)) {
LOGE("Expected 'nbf' field to be a int: type = %s",
ItemTypeToString(*not_before_time_item));
return false;
}
not_before_time_ = not_before_time_item->asInt()->value();
}
// Issued at time "iat" -> int / float
const auto& issued_time_item = cert_map->get(kDiceIssuedAtLabel);
if (issued_time_item) {
if (!IsItemIntType(*issued_time_item)) {
LOGE("Expected 'iat' field to be a int: type = %s",
ItemTypeToString(*issued_time_item));
return false;
}
issued_time_ = issued_time_item->asInt()->value();
}
// CWT ID "cti" => bstr
const auto& cwt_id_item = cert_map->get(kDiceCwtIdLabel);
if (cwt_id_item) {
if (!IsItemBstrType(*cwt_id_item)) {
LOGE("Expected 'cti' field to be a bstr: type = %s",
ItemTypeToString(*cwt_id_item));
return false;
}
cwt_id_ = cwt_id_item->asBstr()->value();
}
// Code Hash "codeHash" => bstr
const auto& code_hash_item = cert_map->get(kDiceCodeHashLabel);
if (code_hash_item) {
if (!IsItemBstrType(*code_hash_item)) {
LOGE("Expected 'codeHash' field to be a bstr: type = %s",
ItemTypeToString(*code_hash_item));
return false;
}
code_hash_ = code_hash_item->asBstr()->value();
}
// Code descriptor "codeDescriptor" => bstr
const auto& code_descriptor_item = cert_map->get(kDiceCodeDescriptorLabel);
if (code_descriptor_item) {
if (!IsItemBstrType(*code_descriptor_item)) {
LOGE("Expected 'codeDescriptor' field to be a bstr: type = %s",
ItemTypeToString(*code_descriptor_item));
return false;
}
code_descriptor_ = code_descriptor_item->asBstr()->value();
}
// Config Hash "configHash" => bstr
const auto& config_hash_item = cert_map->get(kDiceConfigHashLabel);
if (config_hash_item) {
if (!IsItemBstrType(*config_hash_item)) {
LOGE("Expected 'configHash' field to be a bstr: type = %s",
ItemTypeToString(*config_hash_item));
return false;
}
config_hash_ = config_hash_item->asBstr()->value();
}
// Config descriptor "configDescriptor" => bstr
const auto& config_descriptor_item =
cert_map->get(kDiceConfigDescriptorLabel);
if (config_descriptor_item) {
if (!IsItemBstrType(*config_descriptor_item)) {
LOGE("Expected 'configDescriptor' field to be a bstr: type = %s",
ItemTypeToString(*config_descriptor_item));
return false;
}
config_descriptor_ = config_descriptor_item->asBstr()->value();
}
// Authority Hash "configHash" => bstr
const auto& authority_hash_item = cert_map->get(kDiceAuthorityHashLabel);
if (authority_hash_item) {
if (!IsItemBstrType(*authority_hash_item)) {
LOGE("Expected 'authorityHash' field to be a bstr: type = %s",
ItemTypeToString(*authority_hash_item));
return false;
}
authority_hash_ = authority_hash_item->asBstr()->value();
}
// Authority descriptor "authorityDescriptor" => bstr
const auto& authority_descriptor_item =
cert_map->get(kDiceAuthorityDescriptorLabel);
if (authority_descriptor_item) {
if (!IsItemBstrType(*authority_descriptor_item)) {
LOGE("Expected 'authorityDescriptor' field to be a bstr: type = %s",
ItemTypeToString(*authority_descriptor_item));
return false;
}
authority_descriptor_ = authority_descriptor_item->asBstr()->value();
}
// Mode "mode" => bstr .size 1
const auto& mode_item = cert_map->get(kDiceModeLabel);
if (mode_item) {
if (!IsItemBstrType(*mode_item)) {
LOGE("Expected 'mode' field to be a bstr: type = %s",
ItemTypeToString(*mode_item));
return false;
}
const std::vector<uint8_t> mode_bstr = mode_item->asBstr()->value();
mode_ = DecodeModeBytes(mode_bstr);
if (!mode_.has_value()) {
LOGE("Invalid 'mode' format: length = %zu, mode_bstr = %s",
mode_bstr.size(), wvutil::b2a_hex(mode_bstr).c_str());
return false;
}
}
// Subject public key "subjectPublicKey" => bstr
const auto& subject_public_key_item =
cert_map->get(kDiceSubjectPublicKeyLabel);
if (subject_public_key_item) {
if (!IsItemBstrType(*subject_public_key_item)) {
LOGE("Expected 'subjectPublicKey' field to be a bstr: type = %s",
ItemTypeToString(*subject_public_key_item));
return false;
}
subject_public_key_ = subject_public_key_item->asBstr()->value();
}
// Key usage "keyUsage" => bstr .size 1..2
const auto& key_usage_item = cert_map->get(kDiceKeyUsageLabel);
if (key_usage_item) {
if (!IsItemBstrType(*key_usage_item)) {
LOGE("Expected 'keyUsage' field to be a bstr: type = %s",
ItemTypeToString(*key_usage_item));
return false;
}
const std::vector<uint8_t> key_usage_bstr =
key_usage_item->asBstr()->value();
key_usage_ = DecodeKeyUsageBytes(key_usage_bstr);
if (!key_usage_.has_value()) {
LOGE("Invalid 'keyUsage' format: length = %zu, key_usage_bstr = %s",
key_usage_bstr.size(), wvutil::b2a_hex(key_usage_bstr).c_str());
return false;
}
}
// Profile name "profileName" => tstr
const auto& profile_name_item = cert_map->get(kDiceProfileNameLabel);
if (profile_name_item) {
if (!IsItemTstrType(*profile_name_item)) {
LOGE("Expected 'profileName' field to be a tstr: type = %s",
ItemTypeToString(*profile_name_item));
return false;
}
profile_name_ = profile_name_item->asTstr()->value();
}
return true;
}
std::vector<uint8_t> DiceCertData::SerializeCbor() const {
auto cert = cppbor::Map();
if (issuer_.has_value()) {
cert.add(kDiceIssuerLabel, cppbor::Tstr(issuer_.value()));
}
if (subject_.has_value()) {
cert.add(kDiceSubjectLabel, cppbor::Tstr(subject_.value()));
}
if (audience_.has_value()) {
cert.add(kDiceAudienceLabel, cppbor::Tstr(audience_.value()));
}
if (expiration_time_.has_value()) {
cert.add(kDiceExpirationTimeLabel, expiration_time_.value());
}
if (not_before_time_.has_value()) {
cert.add(kDiceNotBeforeLabel, not_before_time_.value());
}
if (issued_time_.has_value()) {
cert.add(kDiceIssuedAtLabel, issued_time_.value());
}
if (cwt_id_.has_value()) {
cert.add(kDiceCwtIdLabel, cppbor::Bstr(cwt_id_.value()));
}
if (code_hash_.has_value()) {
cert.add(kDiceCodeHashLabel, cppbor::Bstr(code_hash_.value()));
}
if (code_descriptor_.has_value()) {
cert.add(kDiceCodeDescriptorLabel, cppbor::Bstr(code_descriptor_.value()));
}
if (config_hash_.has_value()) {
cert.add(kDiceConfigHashLabel, cppbor::Bstr(config_hash_.value()));
}
if (config_descriptor_.has_value()) {
cert.add(kDiceConfigDescriptorLabel,
cppbor::Bstr(config_descriptor_.value()));
}
if (authority_hash_.has_value()) {
cert.add(kDiceAuthorityHashLabel, cppbor::Bstr(authority_hash_.value()));
}
if (authority_descriptor_.has_value()) {
cert.add(kDiceAuthorityDescriptorLabel,
cppbor::Bstr(authority_descriptor_.value()));
}
if (mode_.has_value()) {
cert.add(kDiceModeLabel, cppbor::Bstr(EncodeModeBytes(mode_.value())));
}
if (subject_public_key_.has_value()) {
cert.add(kDiceSubjectPublicKeyLabel,
cppbor::Bstr(subject_public_key_.value()));
}
if (key_usage_.has_value()) {
cert.add(kDiceKeyUsageLabel,
cppbor::Bstr(EncodeKeyUsageBytes(key_usage_.value())));
}
if (profile_name_.has_value()) {
cert.add(kDiceProfileNameLabel, cppbor::Tstr(profile_name_.value()));
}
// All CBOR DICE certs must be canonicalized.
return cert.canonicalize().encode();
}
} // namespace util
} // namespace wvoec

View File

@@ -0,0 +1,561 @@
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation utilities of OEMCrypto APIs
//
#include "dice_cert_utils.h"
#include <inttypes.h>
#include <optional>
#include <string>
#include <vector>
#include <cppbor.h>
#include <gtest/gtest.h>
#include "oemcrypto_ref_test_utils.h"
namespace wvoec {
namespace util {
TEST(DiceCertDataTest, Empty) {
const DiceCertData cert_data;
EXPECT_FALSE(cert_data.has_issuer());
EXPECT_FALSE(cert_data.has_subject());
EXPECT_FALSE(cert_data.has_audience());
EXPECT_FALSE(cert_data.has_expiration_time());
EXPECT_FALSE(cert_data.has_not_before_time());
EXPECT_FALSE(cert_data.has_issued_time());
EXPECT_FALSE(cert_data.has_cwt_id());
EXPECT_FALSE(cert_data.has_code_hash());
EXPECT_FALSE(cert_data.has_code_descriptor());
EXPECT_FALSE(cert_data.has_config_hash());
EXPECT_FALSE(cert_data.has_config_descriptor());
EXPECT_FALSE(cert_data.has_authority_hash());
EXPECT_FALSE(cert_data.has_authority_descriptor());
EXPECT_FALSE(cert_data.has_mode());
EXPECT_FALSE(cert_data.has_subject_public_key());
EXPECT_FALSE(cert_data.has_key_usage());
EXPECT_FALSE(cert_data.has_profile_name());
EXPECT_EQ(cert_data.issuer(), std::nullopt);
EXPECT_EQ(cert_data.subject(), std::nullopt);
EXPECT_EQ(cert_data.audience(), std::nullopt);
EXPECT_EQ(cert_data.expiration_time(), std::nullopt);
EXPECT_EQ(cert_data.not_before_time(), std::nullopt);
EXPECT_EQ(cert_data.issued_time(), std::nullopt);
EXPECT_EQ(cert_data.cwt_id(), std::nullopt);
EXPECT_EQ(cert_data.code_hash(), std::nullopt);
EXPECT_EQ(cert_data.code_descriptor(), std::nullopt);
EXPECT_EQ(cert_data.config_hash(), std::nullopt);
EXPECT_EQ(cert_data.config_descriptor(), std::nullopt);
EXPECT_EQ(cert_data.authority_hash(), std::nullopt);
EXPECT_EQ(cert_data.authority_descriptor(), std::nullopt);
EXPECT_EQ(cert_data.mode(), std::nullopt);
EXPECT_EQ(cert_data.subject_public_key(), std::nullopt);
EXPECT_EQ(cert_data.key_usage(), std::nullopt);
EXPECT_EQ(cert_data.profile_name(), std::nullopt);
}
TEST(DiceCertDataTest, Parse_IssuerOnly) {
const std::string kIssuer = "issuer";
cppbor::Map cert_map;
cert_map.add(kDiceIssuerLabel, cppbor::Tstr(kIssuer));
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_issuer());
EXPECT_FALSE(cert_data.has_subject());
EXPECT_FALSE(cert_data.has_audience());
EXPECT_EQ(cert_data.issuer(), kIssuer);
EXPECT_EQ(cert_data.subject(), std::nullopt);
EXPECT_EQ(cert_data.audience(), std::nullopt);
}
TEST(DiceCertDataTest, Parse_SubjectOnly) {
const std::string kSubject = "subject";
cppbor::Map cert_map;
cert_map.add(kDiceSubjectLabel, cppbor::Tstr(kSubject));
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_FALSE(cert_data.has_issuer());
EXPECT_TRUE(cert_data.has_subject());
EXPECT_FALSE(cert_data.has_audience());
EXPECT_EQ(cert_data.issuer(), std::nullopt);
EXPECT_EQ(cert_data.subject(), kSubject);
EXPECT_EQ(cert_data.audience(), std::nullopt);
}
TEST(DiceCertDataTest, Parse_AudienceOnly) {
const std::string kAudience = "audience";
cppbor::Map cert_map;
cert_map.add(kDiceAudienceLabel, cppbor::Tstr(kAudience));
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_FALSE(cert_data.has_issuer());
EXPECT_FALSE(cert_data.has_subject());
EXPECT_TRUE(cert_data.has_audience());
EXPECT_EQ(cert_data.issuer(), std::nullopt);
EXPECT_EQ(cert_data.subject(), std::nullopt);
EXPECT_EQ(cert_data.audience(), kAudience);
}
TEST(DiceCertDataTest, Parse_ExpirationTimeOnly) {
const int64_t kTime = 12345;
cppbor::Map cert_map;
cert_map.add(kDiceExpirationTimeLabel, kTime);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_expiration_time());
EXPECT_FALSE(cert_data.has_not_before_time());
EXPECT_FALSE(cert_data.has_issued_time());
EXPECT_EQ(cert_data.expiration_time(), kTime);
EXPECT_EQ(cert_data.not_before_time(), std::nullopt);
EXPECT_EQ(cert_data.issued_time(), std::nullopt);
}
TEST(DiceCertDataTest, Parse_NotBeforeTimeOnly) {
const int64_t kTime = 12345;
cppbor::Map cert_map;
cert_map.add(kDiceNotBeforeLabel, kTime);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_FALSE(cert_data.has_expiration_time());
EXPECT_TRUE(cert_data.has_not_before_time());
EXPECT_FALSE(cert_data.has_issued_time());
EXPECT_EQ(cert_data.expiration_time(), std::nullopt);
EXPECT_EQ(cert_data.not_before_time(), kTime);
EXPECT_EQ(cert_data.issued_time(), std::nullopt);
}
TEST(DiceCertDataTest, Parse_IssuedAtTimeOnly) {
const int64_t kTime = 12345;
cppbor::Map cert_map;
cert_map.add(kDiceIssuedAtLabel, kTime);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_FALSE(cert_data.has_expiration_time());
EXPECT_FALSE(cert_data.has_not_before_time());
EXPECT_TRUE(cert_data.has_issued_time());
EXPECT_EQ(cert_data.expiration_time(), std::nullopt);
EXPECT_EQ(cert_data.not_before_time(), std::nullopt);
EXPECT_EQ(cert_data.issued_time(), kTime);
}
TEST(DiceCertDataTest, Parse_ModeOnly) {
const uint8_t kMode = kDiceModeDebug;
const std::vector<uint8_t> kModeBytes = {kMode};
cppbor::Map cert_map;
cert_map.add(kDiceModeLabel, kModeBytes);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_mode());
EXPECT_EQ(cert_data.mode(), kMode);
}
TEST(DiceCertDataTest, Parse_KeyUsageOnly_Zero) {
const DiceKeyUsageFlags kKeyUsage = 0;
// little-endian
const std::vector<uint8_t> kKeyUsageBytes = {0};
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kKeyUsageBytes);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_key_usage());
EXPECT_EQ(cert_data.key_usage(), kKeyUsage);
}
TEST(DiceCertDataTest, Parse_KeyUsageOnly_SingleByte) {
const DiceKeyUsageFlags kKeyUsage = 0x40;
// little-endian
const std::vector<uint8_t> kKeyUsageBytes = {0x40};
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kKeyUsageBytes);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_key_usage());
EXPECT_EQ(cert_data.key_usage(), kKeyUsage);
}
TEST(DiceCertDataTest, Parse_KeyUsageOnly_TwoBytes) {
const DiceKeyUsageFlags kKeyUsage = 0x0245;
// little-endian
const std::vector<uint8_t> kKeyUsageBytes = {0x45, 0x02};
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kKeyUsageBytes);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_key_usage());
EXPECT_EQ(cert_data.key_usage(), kKeyUsage);
}
TEST(DiceCertDataTest, Parse_WidevineCert) {
const std::string kIssuer = "Issuer";
const std::string kSubject = "Subject";
const int64_t kExpiryTime = 3003016585;
const int64_t kNotBeforeTime = 1740798985;
const int64_t kIssuedAtTime = 1740712585;
const std::vector<uint8_t> kCodeHash = RandomData(64);
const std::vector<uint8_t> kConfigHash = RandomData(64);
const std::vector<uint8_t> kConfigDescriptor = RandomData(256);
const std::vector<uint8_t> kAuthorityHash = RandomData(64);
const uint8_t kMode = kDiceModeNormal;
const std::vector<uint8_t> kModeBytes = {kMode};
const std::vector<uint8_t> kSubjectPublicKey = RandomData(512);
const DiceKeyUsageFlags kKeyUsage = kKeyCertSignBit;
const std::vector<uint8_t> kKeyUsageBytes =
DiceCertData::EncodeKeyUsageBytes(kKeyUsage);
const std::string kProfileName = "Widevine";
cppbor::Map cert_map;
cert_map.add(kDiceIssuerLabel, kIssuer);
cert_map.add(kDiceSubjectLabel, kSubject);
// No audience
cert_map.add(kDiceExpirationTimeLabel, kExpiryTime);
cert_map.add(kDiceNotBeforeLabel, kNotBeforeTime);
cert_map.add(kDiceIssuedAtLabel, kIssuedAtTime);
// No CWT ID.
cert_map.add(kDiceCodeHashLabel, kCodeHash);
// No code descriptor.
cert_map.add(kDiceConfigHashLabel, kConfigHash);
cert_map.add(kDiceConfigDescriptorLabel, kConfigDescriptor);
cert_map.add(kDiceAuthorityHashLabel, kAuthorityHash);
// No authority descriptor.
cert_map.add(kDiceModeLabel, kModeBytes);
cert_map.add(kDiceSubjectPublicKeyLabel, kSubjectPublicKey);
cert_map.add(kDiceKeyUsageLabel, kKeyUsageBytes);
cert_map.add(kDiceProfileNameLabel, kProfileName);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
ASSERT_TRUE(cert_data.ParseCbor(cbor_cert));
EXPECT_TRUE(cert_data.has_issuer());
EXPECT_TRUE(cert_data.has_subject());
EXPECT_FALSE(cert_data.has_audience());
EXPECT_TRUE(cert_data.has_expiration_time());
EXPECT_TRUE(cert_data.has_not_before_time());
EXPECT_TRUE(cert_data.has_issued_time());
EXPECT_FALSE(cert_data.has_cwt_id());
EXPECT_TRUE(cert_data.has_code_hash());
EXPECT_FALSE(cert_data.has_code_descriptor());
EXPECT_TRUE(cert_data.has_config_hash());
EXPECT_TRUE(cert_data.has_config_descriptor());
EXPECT_TRUE(cert_data.has_authority_hash());
EXPECT_FALSE(cert_data.has_authority_descriptor());
EXPECT_TRUE(cert_data.has_mode());
EXPECT_TRUE(cert_data.has_subject_public_key());
EXPECT_TRUE(cert_data.has_key_usage());
EXPECT_TRUE(cert_data.has_profile_name());
EXPECT_EQ(cert_data.issuer(), kIssuer);
EXPECT_EQ(cert_data.subject(), kSubject);
EXPECT_EQ(cert_data.audience(), std::nullopt);
EXPECT_EQ(cert_data.expiration_time(), kExpiryTime);
EXPECT_EQ(cert_data.not_before_time(), kNotBeforeTime);
EXPECT_EQ(cert_data.issued_time(), kIssuedAtTime);
EXPECT_EQ(cert_data.cwt_id(), std::nullopt);
EXPECT_EQ(cert_data.code_hash(), kCodeHash);
EXPECT_EQ(cert_data.code_descriptor(), std::nullopt);
EXPECT_EQ(cert_data.config_hash(), kConfigHash);
EXPECT_EQ(cert_data.config_descriptor(), kConfigDescriptor);
EXPECT_EQ(cert_data.authority_hash(), kAuthorityHash);
EXPECT_EQ(cert_data.authority_descriptor(), std::nullopt);
EXPECT_EQ(cert_data.mode(), kMode);
EXPECT_EQ(cert_data.subject_public_key(), kSubjectPublicKey);
EXPECT_EQ(cert_data.key_usage(), kKeyUsage);
EXPECT_EQ(cert_data.profile_name(), kProfileName);
const std::vector<uint8_t> repackaged_cbor_cert = cert_data.SerializeCbor();
ASSERT_FALSE(repackaged_cbor_cert.empty());
EXPECT_EQ(cbor_cert, repackaged_cbor_cert);
}
TEST(DiceCertDataTest, ParseBad_BadIssuerType) {
const int64_t kBadIssuer = 64;
cppbor::Map cert_map;
cert_map.add(kDiceIssuerLabel, kBadIssuer); // Must be tstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadSubjectType) {
const std::vector<uint8_t> kBadSubject = {'b', 's', 't', 'r'};
cppbor::Map cert_map;
cert_map.add(kDiceSubjectLabel, kBadSubject); // Must be tstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadAudienceType) {
const bool kBadAudience = true;
cppbor::Map cert_map;
cert_map.add(kDiceAudienceLabel, cppbor::Bool(kBadAudience)); // Must be tstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadExpirationTimeType) {
cppbor::Map cert_map;
cert_map.add(kDiceExpirationTimeLabel, cppbor::Null()); // Must be int
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadNotBeforeTimeType) {
const std::string kBadNotBeforeTime = "02/27/25";
cppbor::Map cert_map;
cert_map.add(kDiceNotBeforeLabel, kBadNotBeforeTime); // Must be int
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadIssuedAtTimeType) {
const std::vector<uint8_t> kBadIssuedAtTime = {1, 2, 3, 4, 5};
cppbor::Map cert_map;
cert_map.add(kDiceIssuedAtLabel, kBadIssuedAtTime); // Must be int
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadCwtIdType) {
const std::string kBadCwtId = "CWT ID as string";
cppbor::Map cert_map;
cert_map.add(kDiceCwtIdLabel, kBadCwtId); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadCodeHashType) {
const int64_t kBadCodeHash = 1234;
cppbor::Map cert_map;
cert_map.add(kDiceCodeHashLabel, kBadCodeHash); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadCodeDescriptorType) {
cppbor::Map cert_map;
cert_map.add(kDiceCodeDescriptorLabel, cppbor::Null()); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadConfigHashType) {
const int64_t kBadConfigHash = 1234;
cppbor::Map cert_map;
cert_map.add(kDiceConfigHashLabel, kBadConfigHash); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadConfigDescriptorType) {
cppbor::Map cert_map;
cert_map.add(kDiceConfigDescriptorLabel, cppbor::Null()); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadAuthorityHashType) {
const int64_t kBadAuthorityHash = 1234;
cppbor::Map cert_map;
cert_map.add(kDiceAuthorityHashLabel, kBadAuthorityHash); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadAuthorityDescriptorType) {
cppbor::Map cert_map;
cert_map.add(kDiceAuthorityDescriptorLabel, cppbor::Null()); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadModeType) {
const std::string kBadMode = "Normal";
cppbor::Map cert_map;
cert_map.add(kDiceModeLabel, kBadMode); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadModeLength_TooLong) {
const std::vector<uint8_t> kBadMode = {kDiceModeRecovery, 0};
cppbor::Map cert_map;
cert_map.add(kDiceModeLabel, kBadMode);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadModeLength_TooShort) {
const std::vector<uint8_t> kBadMode;
cppbor::Map cert_map;
cert_map.add(kDiceModeLabel, kBadMode);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadSubjectPublicKeyType) {
const std::string kBadSubjectPublicKey = "I'm a key, not!";
cppbor::Map cert_map;
cert_map.add(kDiceSubjectPublicKeyLabel, kBadSubjectPublicKey);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadKeyUsageType) {
const int64_t kBadKeyUsage = 1234;
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kBadKeyUsage); // Must be bstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadKeyUsageLength_TooLong) {
const std::vector<uint8_t> kBadKeyUsage = {0, 0, 1};
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kBadKeyUsage);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadKeyUsageLength_TooShort) {
const std::vector<uint8_t> kBadKeyUsage;
cppbor::Map cert_map;
cert_map.add(kDiceKeyUsageLabel, kBadKeyUsage);
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
TEST(DiceCertDataTest, ParseBad_BadProfileNameType) {
cppbor::Map cert_map;
cert_map.add(kDiceProfileNameLabel, cppbor::Bool(false)); // Must be tstr
const std::vector<uint8_t> cbor_cert = cert_map.canonicalize().encode();
ASSERT_FALSE(cbor_cert.empty());
DiceCertData cert_data;
EXPECT_FALSE(cert_data.ParseCbor(cbor_cert));
}
} // namespace util
} // namespace wvoec