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:
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Android Format Style
|
||||
|
||||
edition = "2021"
|
||||
use_small_heuristics = "Max"
|
||||
newline_style = "Unix"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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',
|
||||
|
||||
346
oemcrypto/util/include/dice_cert_utils.h
Normal file
346
oemcrypto/util/include/dice_cert_utils.h
Normal 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_
|
||||
@@ -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',
|
||||
|
||||
421
oemcrypto/util/src/dice_cert_utils.cpp
Normal file
421
oemcrypto/util/src/dice_cert_utils.cpp
Normal 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
|
||||
561
oemcrypto/util/test/dice_cert_utils_unittest.cpp
Normal file
561
oemcrypto/util/test/dice_cert_utils_unittest.cpp
Normal 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
|
||||
Reference in New Issue
Block a user