OEMCrypto and OPK 18.10.0

GitOrigin-RevId: 987123747bd0be50fc5e4e89ec26eaa6d215bc36
This commit is contained in:
Googler
2025-06-03 11:52:24 -07:00
committed by mattfedd
parent 92146d2468
commit 98f0721662
46 changed files with 1155 additions and 1214 deletions

View File

@@ -2,6 +2,24 @@
[TOC]
## [Version 18.10][v18.10]
### Tests
- Updated `OEMCryptoClientTest.CheckBuildInformation_OutputLengthAPI17` to
accept a returned SHORT_BUFFER size that is larger than the actual required
size.
- Updated `OEMCryptoClientTest.CheckJsonBuildInformationAPI18` to treat the
JSON fields in the `ree` block as optional.
- Added `CorePIGTest.PrintClientAndServerVersionNumber`. Previously this
was only on v19.
### OPK
- OPK_SharedBuffer_Reset optimized to zero out used memory only.
- OPK_BumpAllocator_Reset optimized to zero out used memory only.
- OPKI_ObjectTable mutable struct members separated from immutable members.
## [Version 18.9][v18.9]
This release adds new OEMCrypto APIs to support CAS PVR. It also includes test
@@ -621,3 +639,4 @@ Public release for OEMCrypto API and ODK library version 16.4.
[v18.7]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.7
[v18.8]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.8
[v18.9]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.9
[v18.10]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.10

View File

@@ -33,8 +33,7 @@ void InitLogging() {
void Log(const char* file, const char* function, int line, LogPriority level,
const char* fmt, ...) {
const char* severities[] = {"ERROR", "WARN", "INFO", "DEBUG", "VERBOSE"};
if (level >=
static_cast<LogPriority>(sizeof(severities) / sizeof(*severities))) {
if (static_cast<size_t>(level) >= sizeof(severities) / sizeof(*severities)) {
fprintf(kOutputFile, "[FATAL:%s(%d):%s] Invalid log priority level: %d\n",
file, line, function, level);
return;

View File

@@ -1,159 +0,0 @@
#!/usr/bin/python3
# Copyright 2017 Google LLC. All Rights Reserved.
"""Common test utility functions for OEM certificate generation."""
import datetime
import io
from cryptography import x509
from cryptography.hazmat import backends
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509 import oid
import oem_certificate
_COUNTRY_NAME = 'US'
_STATE_OR_PROVINCE_NAME = 'WA'
_LOCALITY_NAME = 'Kirkland'
_ORGANIZATION_NAME = 'CompanyXYZ'
_ORGANIZATIONAL_UNIT_NAME = 'ContentProtection'
_NOT_VALID_BEFORE = datetime.datetime(2001, 8, 9)
_VALID_DURATION = 100
_LEAF_CERT_VALID_DURATION = 8000
_SYSTEM_ID = 2001
_ROOT_PRIVATE_KEY_PASSPHRASE = b'root_passphrase'
class ArgParseObject(object):
"""A convenient object to allow adding arbitrary attribute to it."""
def create_root_certificate_and_key():
"""Creates a root certificate and key."""
key = rsa.generate_private_key(
public_exponent=65537,
key_size=3072,
backend=backends.default_backend())
subject_name = x509.Name(
[x509.NameAttribute(oid.NameOID.COMMON_NAME, u'root_cert')])
certificate = oem_certificate.build_certificate(
subject_name, subject_name, None,
datetime.datetime(2001, 8, 9), 1000, key.public_key(), key, True)
return (key, certificate)
def setup_csr_args(country_name=_COUNTRY_NAME,
state_or_province_name=_STATE_OR_PROVINCE_NAME,
locality_name=_LOCALITY_NAME,
organization_name=_ORGANIZATION_NAME,
organizational_unit_name=_ORGANIZATIONAL_UNIT_NAME,
key_size=4096,
output_csr_file=None,
output_private_key_file=None,
passphrase=None,
common_name=None):
"""Sets up arguments to OEM Certificate generator for generating csr."""
args = ArgParseObject()
args.key_size = key_size
args.country_name = country_name
args.state_or_province_name = state_or_province_name
args.locality_name = locality_name
args.organization_name = organization_name
args.organizational_unit_name = organizational_unit_name
args.common_name = common_name
if output_csr_file:
args.output_csr_file = output_csr_file
else:
args.output_csr_file = io.BytesIO()
if output_private_key_file:
args.output_private_key_file = output_private_key_file
else:
args.output_private_key_file = io.BytesIO()
args.passphrase = passphrase
return args
def setup_intermediate_cert_args(
csr_bytes, root_key, root_certificate, not_valid_before=_NOT_VALID_BEFORE,
valid_duration=_VALID_DURATION, system_id=_SYSTEM_ID,
root_private_key_passphrase=_ROOT_PRIVATE_KEY_PASSPHRASE,
output_certificate_file=None):
"""Sets up args to OEM Cert generator for generating intermediate cert."""
args = ArgParseObject()
args.not_valid_before = not_valid_before
args.valid_duration = valid_duration
args.system_id = system_id
args.csr_file = io.BytesIO(csr_bytes)
args.root_private_key_passphrase = root_private_key_passphrase
if output_certificate_file:
args.output_certificate_file = output_certificate_file
else:
args.output_certificate_file = io.BytesIO()
serialized_private_key = root_key.private_bytes(
serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(
args.root_private_key_passphrase))
serialized_certificate = root_certificate.public_bytes(
serialization.Encoding.DER)
args.root_certificate_file = io.BytesIO(serialized_certificate)
args.root_private_key_file = io.BytesIO(serialized_private_key)
return args
def setup_leaf_cert_args(intermediate_key_bytes,
intermediate_certificate_bytes,
key_size=1024,
passphrase=None,
not_valid_before=_NOT_VALID_BEFORE,
valid_duration=_LEAF_CERT_VALID_DURATION,
output_certificate_file=None,
output_private_key_file=None):
"""Sets up args to OEM Certificate generator for generating leaf cert."""
args = ArgParseObject()
args.key_size = key_size
args.not_valid_before = not_valid_before
args.valid_duration = valid_duration
args.intermediate_private_key_passphrase = None
if output_certificate_file:
args.output_certificate_file = output_certificate_file
else:
args.output_certificate_file = io.BytesIO()
if output_private_key_file:
args.output_private_key_file = output_private_key_file
else:
args.output_private_key_file = io.BytesIO()
args.passphrase = passphrase
args.intermediate_private_key_file = io.BytesIO(
intermediate_key_bytes)
args.intermediate_certificate_file = io.BytesIO(
intermediate_certificate_bytes)
return args
def create_intermediate_certificate_and_key_bytes(key_size=4096,
passphrase=None,
pem_format=True):
"""Creates an intermediate certificate and key."""
csr_args = setup_csr_args(key_size=key_size, passphrase=passphrase)
oem_certificate.generate_csr(csr_args)
csr_bytes = csr_args.output_csr_file.getvalue()
root_key, root_certificate = create_root_certificate_and_key()
args = setup_intermediate_cert_args(csr_bytes, root_key, root_certificate)
oem_certificate.generate_intermediate_certificate(args)
cert_bytes = args.output_certificate_file.getvalue()
if pem_format:
cert = x509.load_der_x509_certificate(cert_bytes,
backends.default_backend())
cert_bytes = cert.public_bytes(serialization.Encoding.PEM)
return (csr_args.output_private_key_file.getvalue(), cert_bytes)

View File

@@ -3,7 +3,7 @@
// License Agreement.
/**
* @mainpage OEMCrypto API v18.9
* @mainpage OEMCrypto API v18.10
*
* OEMCrypto is the low level library implemented by the OEM to provide key and
* content protection, usually in a separate secure memory or process space. The
@@ -1138,7 +1138,10 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
* state, an error of OEMCrypto_ERROR_INVALID_CONTEXT is returned.
*
* @param[in] session: handle for the session to be used.
* @param[out] nonce: pointer to memory to receive the computed nonce.
* @param[out] nonce pointer to memory to receive the computed nonce. The nonce
* will only be stored into this memory location if the function returns
* OEMCrypto_SUCCESS. If any other OEMCryptoResult is returned, the contents
* of the memory pointed to by nonce will remain unchanged.
*
* Results:
* nonce: the nonce is also stored in secure memory.
@@ -1163,17 +1166,15 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
/**
* OEMCrypto will use ODK_PrepareCoreLicenseRequest to prepare the core
* message. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall sign the
* message body using the DRM certificate's private key. If it returns an
* error, the error should be returned by OEMCrypto to the CDM layer.
* message. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall generate
* a signature over the whole message buffer (includes both the prepared
* core message and message body), using the DRM certificate's private
* key. If ODK returns an error, the error should be returned by OEMCrypto
* to the CDM layer.
*
* ODK_PrepareCoreLicenseRequest is described in the document "Widevine Core
* Message Serialization".
*
* The message body is the buffer starting at message + core_message_size,
* and with length message_length - core_message_size. The reason OEMCrypto
* only signs the message body and not the entire message is to allow a v16
* device to request a license from a v15 license server.
*
* If the session's private RSA key has an "allowed_schemes" bit field, then
* it must be 0x1 (RSASSA-PSS with SHA1). If not, then an error of
* OEMCrypto_ERROR_SIGNATURE_FAILURE shall be returned.
@@ -1238,22 +1239,16 @@ OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest(
* document "Widevine Core Message Serialization", to prepare the core
* message.
*
* If it returns an error, the error should be returned by OEMCrypto to the
* CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto computes the
* signature using the renewal mac key which was delivered in the license via
* LoadLicense.
* If ODK returns an error, the error should be returned by OEMCrypto to the
* CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall generate
* the signature using the following rules:
*
* If nonce_values.api_level is 16, then OEMCrypto shall compute the
* signature of the entire message using the session's client renewal mac
* key. The entire message is the buffer starting at message with length
* message_length.
*
* If nonce_values.api_major_version is 15, then OEMCrypto shall compute the
* signature of the message body using the session's client renewal mac key.
* The message body is the buffer starting at message+core_message_size with
* length message_length - core_message_size. If the session has not had a
* license loaded, it will use the usage entries client mac key to sign the
* message body.
* 1. If nonce_values.api_major_version is 16, then the signature shall
* be generated over the message body (message buffer starting after
* the core message).
* 2. If nonce_values.api_major_version is greated than 16, then the
* signature shall be generated over the whole message (includes both
* the prepared core message and message body).
*
* This function generates a HMAC-SHA256 signature using the mac_key[client]
* for license request signing under the license server protocol for CENC.
@@ -3520,7 +3515,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
@@ -4118,8 +4115,8 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
* support the alternative signing algorithms may refuse to load these keys
* and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case
* for these alternative signing algorithms is to support devices that use
* X509 certificates for authentication when acting as a ChromeCast receiver.
* This is not needed for devices that wish to send data to a ChromeCast.
* X509 certificates for authentication when acting as a Google Cast receiver.
* This is not needed for devices that wish to send data to a Google Cast.
*
* If the first four bytes of the buffer `enc_private_key` are not the string
* "SIGN", then this key may not be used with OEMCrypto_GenerateRSASignature().
@@ -4151,8 +4148,8 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
* algorithms may refuse to load these keys and return an error of
* OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these
* alternative signing algorithms is to support devices that use X.509
* certificates for authentication when acting as a ChromeCast receiver.
* This is not needed for devices that wish to send data to a ChromeCast.
* certificates for authentication when acting as a Google Cast receiver.
* This is not needed for devices that wish to send data to a Google Cast.
* 7. If the first four bytes of the buffer private_key are not the string
* "SIGN", this key may not be used with OEMCrypto_GenerateRSASignature().
* 8. After possibly skipping past the first 8 bytes signifying the allowed
@@ -4320,7 +4317,7 @@ OEMCryptoResult OEMCrypto_LoadTestRSAKey(void);
*
* The second padding scheme is for devices that use X509 certificates for
* authentication. The main example is devices that work as a Cast receiver,
* like a ChromeCast, not for devices that wish to send to the Cast device,
* like a Google Cast, not for devices that wish to send to the Cast device,
* such as almost all Android devices. OEMs that do not support X509
* certificate authentication need not implement this function and can return
* OEMCrypto_ERROR_NOT_IMPLEMENTED.

View File

@@ -1,635 +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_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 _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 _lcc99
#define Level3_LoadRenewal _lcc101
#define Level3_LoadProvisioning _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_UseSecondaryKey _lcc142
#define Level3_GetEmbeddedDrmCertificate _lcc143
#define Level3_MarkOfflineSession _lcc144
// Added in OEMCrypto v19.3, but back ported to v18
#define Level3_SetSessionUsage _lcc155
#define Level3_GetPVRKey _lcc157
#define Level3_LoadPVRKey _lcc158
#else
#define Level3_Initialize _oecc01
#define Level3_Terminate _oecc02
#define Level3_InstallKeyboxOrOEMCert _oecc03
#define Level3_GetKeyData _oecc04
#define Level3_IsKeyboxOrOEMCertValid _oecc05
#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 _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 _oecc99
#define Level3_LoadRenewal _oecc101
#define Level3_LoadProvisioning _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
// Internal-only.
#define Level3_GetEmbeddedDrmCertificate _oecc143
#define Level3_UseSecondaryKey _oecc144
#define Level3_MarkOfflineSession _oecc145
// Added in OEMCrypto v19.3, but back ported to v18
#define Level3_SetSessionUsage _oecc155
#define Level3_GetPVRKey _oecc157
#define Level3_LoadPVRKey _oecc158
#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_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(
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);
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(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,
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_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);
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_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);
// The following are specific to Google's Level 3 implementation and are not
// required.
enum Level3InitializationState {
LEVEL3_INITIALIZATION_SUCCESS = 0,
LEVEL3_INITIALIZATION_UNKNOWN_FAILURE = 1,
LEVEL3_SEED_FAILURE = 2,
LEVEL3_SAVE_DEVICE_KEYS_FAILURE = 3,
LEVEL3_READ_DEVICE_KEYS_FAILURE = 4,
LEVEL3_VERIFY_DEVICE_KEYS_FAILURE = 5,
};
enum Level3RunningMode {
LEVEL3_MODE_HAYSTACK_ONLY = 0,
LEVEL3_MODE_RIKERS_DEFAULT = 1,
LEVEL3_MODE_RIKERS_ONLY = 2,
};
/*
* Level3_GetRunningMode
*
* Description:
* Returns the current mode the Level3 is running in. This shouldn't change
* while the processes is running.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Version:
* This method is new in API version 19.
*/
Level3RunningMode Level3_GetRunningMode(void);
/*
* Level3_GetInitializationState
*
* Description:
* Return any warning or error condition which occurred during
* initialization. On some platforms, this value will be logged and metrics
* will be gathered on production devices. This is an optional feature, and
* OEMCrypto may always return 0, even if Level3_Initialize failed. This
* function may be called whether Level3_Initialize succeeded or not.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Returns:
* LEVEL3_INITIALIZATION_SUCCESS - no warnings or errors during initialization
* LEVEL3_SEED_FAILURE - error in seeding the software RNG
* LEVEL3_SAVE_DEVICE_KEYS_FAILURE - failed to save device keys to file system
* LEVEL3_READ_DEVICE_KEYS_FAILURE - failed to read device keys from file
* system
* LEVEL3_VERIFY_DEVICE_KEYS_FAILURE - failed to verify decrypted device keys
*
* Version:
* This method is new in API version 14.
*/
Level3InitializationState Level3_GetInitializationState(void);
/*
* Level3_OutputErrorLogs
*
* Description:
* Call to output any errors in the Level 3 execution if the Level 3 has
* failed. This method should only be called if the Level 3 has failed in
* an unrecoverable state, and needs to be reinitialized.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running.
*
* Returns:
* N/A
*
* Version:
* This method is new in API version 15.
*/
void Level3_OutputErrorLogs();
} // extern "C"
namespace wvoec3 {
// The following are interfaces needed for Google's Level 3 OEMCrypto
// specifically, which partners are expected to implement.
// Returns a stable, unique identifier for the device. This could be a
// serial number or any other character sequence representing that device.
// The parameter |len| needs to be changed to reflect the length of the
// unique identifier.
const char* getUniqueID(size_t* len);
// Returns a 64-bit unsigned integer to be used as a random seed for RNG.
// If the operation is unsuccessful, this function returns 0.
// We provide a sample implementation under the name generate_entropy_linux.cpp
// which partners should use if they can.
uint64_t generate_entropy();
// Creates and returns an OEMCrypto_Level3FileSystem implementation.
OEMCrypto_Level3FileSystem* createLevel3FileSystem();
// Deletes the pointer retrieved by the function above.
void deleteLevel3FileSystem(OEMCrypto_Level3FileSystem* file_system);
} // namespace wvoec3
#endif // LEVEL3_OEMCRYPTO_H_

View File

@@ -1,32 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
/*********************************************************************
* level3_file_system.h
*
* File system for OEMCrypto Level3 file operations.
*********************************************************************/
#ifndef LEVEL3_FILE_SYSTEM_H_
#define LEVEL3_FILE_SYSTEM_H_
#include <stdlib.h>
#include "platform.h"
namespace wvoec3 {
class OEMCrypto_Level3FileSystem {
public:
virtual ~OEMCrypto_Level3FileSystem() {}
virtual ssize_t Read(const char *filename, void *buffer, size_t size) = 0;
virtual ssize_t Write(const char *filename, const void *buffer,
size_t size) = 0;
virtual bool Exists(const char *filename) = 0;
virtual ssize_t FileSize(const char *filename) = 0;
virtual bool Remove(const char *filename) = 0;
};
} // namespace wvoec3
#endif

View File

@@ -26,9 +26,9 @@ struct CoreMessageFeatures {
// This is the published version of the ODK Core Message library. The default
// behavior is for the server to restrict messages to at most this version
// number. The default is 18.9.
// number. The default is 18.10.
uint32_t maximum_major_version = 18;
uint32_t maximum_minor_version = 9;
uint32_t maximum_minor_version = 10;
bool operator==(const CoreMessageFeatures &other) const;
bool operator!=(const CoreMessageFeatures &other) const {

View File

@@ -16,10 +16,10 @@ extern "C" {
/* The version of this library. */
#define ODK_MAJOR_VERSION 18
#define ODK_MINOR_VERSION 9
#define ODK_MINOR_VERSION 10
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v18.9 2025-03-11"
#define ODK_RELEASE_DATE "ODK v18.10 2025-06-03"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16

View File

@@ -76,7 +76,8 @@ bool ParseRequest(uint32_t message_type,
!(message_type == ODK_Renewal_Request_Type &&
core_message.message_type == ODK_Release_Request_Type) &&
!(message_type == ODK_Provisioning_Request_Type &&
core_message.message_type == ODK_Renewed_Provisioning_Request_Type)) {
(core_message.message_type == ODK_Renewed_Provisioning_Request_Type ||
core_message.message_type == ODK_Provisioning40_Request_Type))) {
return false;
}
// Verify that the amount of buffer we read, which is GetOffset, is not more
@@ -87,10 +88,8 @@ bool ParseRequest(uint32_t message_type,
return true;
}
} // namespace
static bool GetNonceFromMessage(const std::string& oemcrypto_core_message,
ODK_NonceValues* nonce_values) {
bool GetNonceFromMessage(const std::string& oemcrypto_core_message,
ODK_NonceValues* nonce_values) {
if (nonce_values == nullptr) return false;
if (oemcrypto_core_message.size() < sizeof(ODK_CoreMessage)) return false;
@@ -123,6 +122,8 @@ bool CopyCounterInfo(ODK_MessageCounter* dest, ODK_MessageCounterInfo* src) {
return true;
}
} // namespace
bool CoreLicenseRequestFromMessage(const std::string& oemcrypto_core_message,
ODK_LicenseRequest* core_license_request) {
ODK_NonceValues nonce;

View File

@@ -30,7 +30,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
features.maximum_minor_version = 2; // 17.2
break;
case 18:
features.maximum_minor_version = 9; // 18.9
features.maximum_minor_version = 10; // 18.10
break;
default:
features.maximum_minor_version = 0;

View File

@@ -274,7 +274,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
nonce_values->api_minor_version = 2;
break;
case 18:
nonce_values->api_minor_version = 9;
nonce_values->api_minor_version = 10;
break;
default:
nonce_values->api_minor_version = 0;

View File

@@ -1216,7 +1216,7 @@ std::vector<VersionParameters> TestCases() {
// number.
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 9},
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 10},
// Here are some known good versions. Make extra sure they work.
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
@@ -1232,6 +1232,7 @@ std::vector<VersionParameters> TestCases() {
{ODK_MAJOR_VERSION, 18, 7, 18, 7},
{ODK_MAJOR_VERSION, 18, 8, 18, 8},
{ODK_MAJOR_VERSION, 18, 9, 18, 9},
{ODK_MAJOR_VERSION, 18, 10, 18, 10},
{0, 16, 3, 16, 3},
{0, 16, 4, 16, 4},
{0, 16, 5, 16, 5},
@@ -1243,6 +1244,7 @@ std::vector<VersionParameters> TestCases() {
{0, 18, 7, 18, 7},
{0, 18, 8, 18, 8},
{0, 18, 9, 18, 9},
{0, 18, 10, 18, 10},
};
return test_cases;
}

View File

@@ -40,6 +40,10 @@
#include "wtpi_provisioning_4_interface.h"
#include "wtpi_root_of_trust_interface_layer1.h"
#ifdef USE_REF_BACK_COMPAT
# include "wtpi_ref_compat_interface.h"
#endif
typedef enum GlobalSystemState {
SYSTEM_NOT_INITIALIZED = (int)0x2ca77206,
SYSTEM_INITIALIZED = (int)0xf57fab49
@@ -2860,16 +2864,71 @@ OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(OEMCrypto_SESSION session,
result = OPKI_CheckStatePreCall(session_context, API_LOADDRMPRIVATEKEY);
if (result != OEMCrypto_SUCCESS) return result;
const uint8_t* drm_key = wrapped_drm_key;
size_t drm_key_length = wrapped_drm_key_length;
WTPI_AsymmetricKey_Handle private_key_handle;
uint32_t allowed_schemes;
result = WTPI_UnwrapIntoAsymmetricKeyHandle(
DEVICE_KEY_WRAP_DRM_CERT, wrapped_drm_key, wrapped_drm_key_length,
drm_key_type, &private_key_handle, &allowed_schemes);
#ifdef USE_REF_BACK_COMPAT
uint8_t new_wrapped_drm_key[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE];
size_t new_wrapped_drm_key_length = 0;
if (result != OEMCrypto_SUCCESS) {
LOGW("Failed to unwrap DRM private key into key handle with result: %u",
result);
// A v16-wrapped RSA key will fail to unwrap with WTPI_Unwrap*
// In this case, we need to intercept that failure and try to unwrap using
// the "reference" method.
uint8_t clear_drm_key[PKCS8_DRM_KEY_MAX_SIZE];
size_t clear_drm_key_length = sizeof(clear_drm_key);
result = WTPI_RefCompat_UnwrapRSA(wrapped_drm_key, wrapped_drm_key_length,
clear_drm_key, &clear_drm_key_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("unwrap back compat failed with result %d", result);
return result;
}
// Rewrap it with current scheme, then continue as usual.
// OPKI_LoadDRMKey() requires a wrapped key, so we have to rewrap.
result = WTPI_GetWrappedAsymmetricKeySize(
clear_drm_key_length, DRM_RSA_PRIVATE_KEY, &new_wrapped_drm_key_length);
if (result != OEMCrypto_SUCCESS) {
WTPI_SecureZeroMemory(clear_drm_key, clear_drm_key_length);
return result;
}
result =
WTPI_WrapAsymmetricKey(DEVICE_KEY_WRAP_DRM_CERT, new_wrapped_drm_key,
new_wrapped_drm_key_length, drm_key_type,
clear_drm_key, clear_drm_key_length);
WTPI_SecureZeroMemory(clear_drm_key, clear_drm_key_length);
if (result != OEMCrypto_SUCCESS) {
return result;
}
// This validates the wrapped key and lets us get the signature size.
result = WTPI_UnwrapIntoAsymmetricKeyHandle(
DEVICE_KEY_WRAP_DRM_CERT, new_wrapped_drm_key,
new_wrapped_drm_key_length, drm_key_type, &private_key_handle,
&allowed_schemes);
if (result != OEMCrypto_SUCCESS) {
return result;
}
drm_key = new_wrapped_drm_key;
drm_key_length = new_wrapped_drm_key_length;
}
#else
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to unwrap DRM private key into key handle with result: %u",
result);
return result;
}
#endif
size_t signature_size;
result = WTPI_GetSignatureSize(private_key_handle, &signature_size);
WTPI_FreeAsymmetricKeyHandle(private_key_handle);
@@ -2878,9 +2937,8 @@ OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(OEMCrypto_SESSION session,
return result;
}
result =
OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key,
wrapped_drm_key_length, signature_size, allowed_schemes);
result = OPKI_LoadDRMKey(session_context, drm_key_type, drm_key,
drm_key_length, signature_size, allowed_schemes);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to load DRM key");
goto cleanup;
@@ -3490,10 +3548,11 @@ OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
OEMCryptoResult result =
GetSessionContext(key_session, &session_context, &key_session_context);
if (result != OEMCrypto_SUCCESS) {
// In case that the entitlement session is closed prior to the entitled key
// session, the result of OPKI_GetSession() will not be OEMCrypto_SUCCESS,
// and that's ok. This entitled key session should already be released when
// its entitlement session was closed. Just return success here.
// In case that the entitlement session is closed prior to the entitled
// key session, the result of OPKI_GetSession() will not be
// OEMCrypto_SUCCESS, and that's ok. This entitled key session should
// already be released when its entitlement session was closed. Just
// return success here.
return OEMCrypto_SUCCESS;
}
ABORT_IF(session_context == NULL,
@@ -3867,8 +3926,8 @@ OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
}
/* Validations to be done before re-associating an entitled key session to a
* new entitlement session:
* 1. at least one entitled key is supposed to have its entitlement key found
* in the new session
* 1. at least one entitled key is supposed to have its entitlement key
* found in the new session
* 2. for any entitled key, if its entitlement key is found in the new
* session, then the key control block should remain unchanged in the new
* session, compared to the one in the existing entitlement session */
@@ -3879,8 +3938,8 @@ OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
* with. */
const EntitlementKeyInfo* key_info =
&key_session_context->entitlement_keys[i];
/* Finds the entitlement key in the new entitlement session. It is ok if an
* entitled key doesn't have an entitlement key in the new entitlement
/* Finds the entitlement key in the new entitlement session. It is ok if
* an entitled key doesn't have an entitlement key in the new entitlement
* session. The entitled key will be ignored in this case. */
for (uint32_t k = 0; k < entitlement_session_context->num_entitlement_keys;
k++) {
@@ -4019,16 +4078,16 @@ OEMCryptoResult OEMCrypto_LoadCasECMKeys(
goto cleanup;
}
/* Initialized the index to which the entitled content key to be loaded. */
/* Initialized the index to which the entitled content key to be loaded.
*/
uint32_t entitled_content_key_index =
key_session->num_entitled_content_keys;
/* It prefers to reuse an existing content key index that is entitled by the
* same entitlement key if one exists already, but will allocate a new index
* if there are none that can be reused.
* The block below searches whether there is an existing content key
* entitled by the same entitlement key, with the same parity as the key to
* be loaded, and will reuse the index to load the new content key if there
* is one. */
/* It prefers to reuse an existing content key index that is entitled by
* the same entitlement key if one exists already, but will allocate a new
* index if there are none that can be reused. The block below searches
* whether there is an existing content key entitled by the same
* entitlement key, with the same parity as the key to be loaded, and will
* reuse the index to load the new content key if there is one. */
for (uint32_t k = 0; k < key_session->num_entitled_content_keys; k++) {
const EntitlementKeyInfo* key_info = &key_session->entitlement_keys[k];
if (key_info->entitlement_key_id_size == entitlement_key->key_id_size &&

View File

@@ -34,7 +34,7 @@
// version bumps to v17.1, the first released OPK implementation would be
// v17.1.0
#define API_MAJOR_VERSION 18
#define API_MINOR_VERSION 9
#define API_MINOR_VERSION 10
#define OPK_PATCH_VERSION 0
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */

View File

@@ -7,11 +7,12 @@
#include "oemcrypto_check_macros.h"
#include "wtpi_logging_interface.h"
static void* UnsafeGetElem(OPKI_ObjectTable* table, uint32_t index) {
static void* UnsafeGetElem(const OPKI_ObjectTable* table, uint32_t index) {
return (char*)table->elems + index * table->elem_size;
}
void* OPKI_AllocFromObjectTable(OPKI_ObjectTable* table, uint32_t* index) {
void* OPKI_AllocFromObjectTable(const OPKI_ObjectTable* table,
uint32_t* index) {
if (!table) return NULL;
if (table->next_free[0] == 0) {
// This should be impossible, so this means we aren't initialized yet (since
@@ -21,16 +22,17 @@ void* OPKI_AllocFromObjectTable(OPKI_ObjectTable* table, uint32_t* index) {
}
}
const uint32_t new_index = table->first_free;
const uint32_t new_index = table->mutable_members->first_free;
if (new_index == table->capacity) return NULL;
if (index) *index = new_index;
table->first_free = table->next_free[new_index];
table->mutable_members->first_free = table->next_free[new_index];
ABORT_IF(table->is_used[new_index], "Inconsistent free list");
table->is_used[new_index] = true;
return UnsafeGetElem(table, new_index);
}
OEMCryptoResult OPKI_FreeFromObjectTable(OPKI_ObjectTable* table, void* elem) {
OEMCryptoResult OPKI_FreeFromObjectTable(const OPKI_ObjectTable* table,
void* elem) {
if (!table) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (!elem) return OEMCrypto_SUCCESS;
@@ -43,7 +45,7 @@ OEMCryptoResult OPKI_FreeFromObjectTable(OPKI_ObjectTable* table, void* elem) {
return OPKI_FreeFromObjectTableByIndex(table, index);
}
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(OPKI_ObjectTable* table,
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(const OPKI_ObjectTable* table,
uint32_t index) {
if (!table) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (index >= table->capacity) {
@@ -60,30 +62,30 @@ OEMCryptoResult OPKI_FreeFromObjectTableByIndex(OPKI_ObjectTable* table,
if (result != OEMCrypto_SUCCESS) return result;
}
table->next_free[index] = table->first_free;
table->first_free = index;
table->next_free[index] = table->mutable_members->first_free;
table->mutable_members->first_free = index;
table->is_used[index] = false;
return OEMCrypto_SUCCESS;
}
void* OPKI_GetFromObjectTable(OPKI_ObjectTable* table, uint32_t index) {
void* OPKI_GetFromObjectTable(const OPKI_ObjectTable* table, uint32_t index) {
if (!table || index >= table->capacity || !table->is_used[index]) {
return NULL;
}
return UnsafeGetElem(table, index);
}
void OPKI_UnsafeClearObjectTable(OPKI_ObjectTable* table) {
void OPKI_UnsafeClearObjectTable(const OPKI_ObjectTable* table) {
if (!table) return;
for (uint32_t i = 0; i < table->capacity; i++) {
table->next_free[i] = i + 1;
table->is_used[i] = false;
}
table->first_free = 0;
table->mutable_members->first_free = 0;
}
uint32_t OPKI_GetObjectTableUseCount(OPKI_ObjectTable* table) {
uint32_t OPKI_GetObjectTableUseCount(const OPKI_ObjectTable* table) {
if (!table) return 0;
uint32_t ret = 0;
for (uint32_t index = 0; index < table->capacity; index++) {

View File

@@ -15,15 +15,19 @@
extern "C" {
#endif
typedef struct OPKI_ObjectTableMutableMembers {
uint32_t first_free;
} OPKI_ObjectTableMutableMembers;
typedef struct OPKI_ObjectTable {
uint32_t capacity;
size_t elem_size;
uint32_t first_free;
// Note, the argument pointer can be a pointer to any type.
OEMCryptoResult (*dtor)(void*);
void* elems;
uint32_t* next_free;
bool* is_used;
OPKI_ObjectTableMutableMembers* mutable_members;
} OPKI_ObjectTable;
/**
@@ -36,14 +40,15 @@ typedef struct OPKI_ObjectTable {
/* Note these arrays are initialized to 0. */ \
static uint32_t var_name##_next_free[(max_count)]; \
static bool var_name##_is_used[(max_count)]; \
static OPKI_ObjectTable var_name = { \
static OPKI_ObjectTableMutableMembers var_name##_mutable_members; \
static const OPKI_ObjectTable var_name = { \
.capacity = (max_count), \
.elem_size = sizeof(type_name), \
.dtor = dtor_arg, \
.first_free = 0, \
.elems = var_name##_elems, \
.next_free = var_name##_next_free, \
.is_used = var_name##_is_used, \
.mutable_members = &var_name##_mutable_members, \
}
/**
@@ -51,30 +56,31 @@ typedef struct OPKI_ObjectTable {
* no more free elements. If |index| is not null, it will be filled with the
* index of the new object.
*/
void* OPKI_AllocFromObjectTable(OPKI_ObjectTable* table, uint32_t* index);
void* OPKI_AllocFromObjectTable(const OPKI_ObjectTable* table, uint32_t* index);
/**
* Frees an object and makes it available for allocation. If the table was
* given a destructor, this calls it. If the destructor fails, the object is
* still allocated in the table.
*/
OEMCryptoResult OPKI_FreeFromObjectTable(OPKI_ObjectTable* table, void* elem);
OEMCryptoResult OPKI_FreeFromObjectTable(const OPKI_ObjectTable* table,
void* elem);
/** The same as FreeFromObjectTable, but gives an index instead. */
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(OPKI_ObjectTable* table,
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(const OPKI_ObjectTable* table,
uint32_t index);
/** Gets the object at the given index, or NULL if not valid. */
void* OPKI_GetFromObjectTable(OPKI_ObjectTable* table, uint32_t index);
void* OPKI_GetFromObjectTable(const OPKI_ObjectTable* table, uint32_t index);
/**
* Deletes all objects from the table, allowing any to be used again. This
* does NOT invoke destructors
*/
void OPKI_UnsafeClearObjectTable(OPKI_ObjectTable* table);
void OPKI_UnsafeClearObjectTable(const OPKI_ObjectTable* table);
/** Gets the number of objects used from the given table. */
uint32_t OPKI_GetObjectTableUseCount(OPKI_ObjectTable* table);
uint32_t OPKI_GetObjectTableUseCount(const OPKI_ObjectTable* table);
#ifdef __cplusplus
} // extern "C"

View File

@@ -27,7 +27,6 @@
#include "wtpi_device_key_interface.h"
#include "wtpi_logging_interface.h"
#include "wtpi_root_of_trust_interface_layer1.h"
#include "wtpi_device_key_interface.h"
NO_IGNORE_RESULT static bool IsSupportedDrmKeyType(AsymmetricKeyType key_type) {
return key_type == DRM_RSA_PRIVATE_KEY || key_type == DRM_ECC_PRIVATE_KEY;

View File

@@ -18,6 +18,7 @@
#include "wtpi_device_key_interface.h"
#include "wtpi_generation_number_interface.h"
#include "wtpi_logging_interface.h"
#include "wtpi_ref_compat_interface.h"
/**
The usage table consists of a short array of active entries, and a large
@@ -130,43 +131,78 @@ static UsageEntry* FindUsageEntry(OEMCrypto_SESSION session_id) {
return NULL;
}
/* This serializes, encrypts, and signs the current header into the given
* buffer. It is an error if the buffer is not big enough. The header fields
* and the master generation number in the current header will be updated. */
NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignHeader(
uint8_t* header_buffer, size_t header_buffer_length) {
SavedUsageHeader header = {
static OEMCryptoResult InitHeader(SavedUsageHeader* header,
const UsageTable* usage_table) {
if (!header || !usage_table) return OEMCrypto_ERROR_INVALID_CONTEXT;
*header = (SavedUsageHeader){
.common_info =
{
.file_type = USAGE_TABLE_HEADER,
.format_version = CURRENT_FILE_FORMAT_VERSION,
},
.master_generation_number = g_usage_table.master_generation_number,
.table_size = g_usage_table.table_size,
.master_generation_number = usage_table->master_generation_number,
.table_size = usage_table->table_size,
};
memcpy(header.generation_numbers, g_usage_table.generation_numbers,
header.table_size * sizeof(uint64_t));
SignedSavedUsageHeader signed_header = {
memcpy(header->generation_numbers, usage_table->generation_numbers,
header->table_size * sizeof(uint64_t));
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult InitSignedHeader(SignedSavedUsageHeader* signed_header) {
if (!signed_header) return OEMCrypto_ERROR_INVALID_CONTEXT;
*signed_header = (SignedSavedUsageHeader){
.common_info =
{
.file_type = SIGNED_USAGE_TABLE_HEADER,
.format_version = CURRENT_FILE_FORMAT_VERSION,
},
.buffer_size = sizeof(signed_header.buffer),
.buffer_size = sizeof(signed_header->buffer),
.buffer = {0},
};
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult WrapHeader(SavedUsageHeader* header, uint8_t* out_buffer,
size_t out_buffer_length) {
if (!header) return OEMCrypto_ERROR_INVALID_CONTEXT;
uint8_t temp_buffer[PADDED_HEADER_BUFFER_SIZE] = {0};
OEMCryptoResult result =
OPKI_PackUsageHeader(temp_buffer, sizeof(temp_buffer), &header);
OPKI_PackUsageHeader(temp_buffer, sizeof(temp_buffer), header);
if (result != OEMCrypto_SUCCESS) return result;
SignedSavedUsageHeader signed_header;
result = InitSignedHeader(&signed_header);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_EncryptAndSign(DEVICE_KEY_WRAP_USAGE_TABLE, temp_buffer,
sizeof(temp_buffer), signed_header.buffer,
&signed_header.buffer_size);
if (result != OEMCrypto_SUCCESS) return result;
result = OPKI_PackSignedUsageHeader(header_buffer, header_buffer_length,
&signed_header);
result =
OPKI_PackSignedUsageHeader(out_buffer, out_buffer_length, &signed_header);
return result;
}
/* This serializes, encrypts, and signs the current header into the given
* buffer. It is an error if the buffer is not big enough.
* Copies the generation numbers from the supplied usage_table parameter into
* the serialized header fields.
*/
NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignHeader(
uint8_t* header_buffer, size_t header_buffer_length,
const UsageTable* usage_table) {
SavedUsageHeader header;
OEMCryptoResult result = InitHeader(&header, usage_table);
if (result != OEMCrypto_SUCCESS) return result;
result = WrapHeader(&header, header_buffer, header_buffer_length);
return result;
}
@@ -241,9 +277,48 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyHeader(
LOGE("Invalid header buffer size: %zu", header_buffer_length);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
const uint8_t* buffer = header_buffer;
size_t buffer_length = header_buffer_length;
SavedCommonInfo common_info;
OEMCryptoResult result = OPKI_UnpackSavedCommonInfo(
header_buffer, header_buffer_length, &common_info);
OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
#ifdef USE_REF_BACK_COMPAT
// To deal with reference-wrapped v16 usage tables, extract the info and
// rewrap. Then continue as usual with the rewrapped blob.
// Reference usage table doesn't have any kind of common_info struct at the
// top. Previously, fail immediatley if the common_info doesn't match
// expectations. Now, check if none of the common_info data makes sense, then
// try v16.
result = OPKI_UnpackSavedCommonInfo(buffer, buffer_length, &common_info);
if (result != OEMCrypto_SUCCESS) return result;
bool should_try_ref_compat =
(common_info.file_type != SIGNED_USAGE_TABLE_HEADER &&
common_info.file_type != SIGNED_USAGE_TABLE_ENTRY &&
common_info.file_type != USAGE_TABLE_HEADER &&
common_info.file_type != USAGE_TABLE_ENTRY);
SavedUsageHeader temp_header = {0};
uint8_t rewrapped_header[sizeof(SignedSavedUsageHeader)] = {0};
size_t rewrapped_header_size = sizeof(rewrapped_header);
if (should_try_ref_compat) {
// Unwrap into current OPK struct
result =
WTPI_RefCompat_UnwrapUsageHeader(buffer, buffer_length, &temp_header);
if (result != OEMCrypto_SUCCESS) return result;
// Rewrap struct with current wrapping scheme
result = WrapHeader(&temp_header, rewrapped_header, rewrapped_header_size);
if (result != OEMCrypto_SUCCESS) return result;
// Point variables to use new rewrapped data, start the process again
buffer = rewrapped_header;
buffer_length = rewrapped_header_size;
}
#endif
result = OPKI_UnpackSavedCommonInfo(buffer, buffer_length, &common_info);
if (result != OEMCrypto_SUCCESS) return result;
if (common_info.file_type != SIGNED_USAGE_TABLE_HEADER) {
/* We were given the wrong file. */
@@ -253,8 +328,7 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyHeader(
if (common_info.format_version == LEGACY_FILE_FORMAT_VERSION) {
LOGD("Legacy usage header format version %u detected.",
LEGACY_FILE_FORMAT_VERSION);
return DecryptAndVerifyHeader_Legacy(header_buffer, header_buffer_length,
header);
return DecryptAndVerifyHeader_Legacy(buffer, buffer_length, header);
}
if (common_info.format_version != CURRENT_FILE_FORMAT_VERSION) {
LOGE("Bad signed usage header format version: %u",
@@ -262,8 +336,7 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyHeader(
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SignedSavedUsageHeader signed_header;
result = OPKI_UnpackSignedUsageHeader(header_buffer, header_buffer_length,
&signed_header);
result = OPKI_UnpackSignedUsageHeader(buffer, buffer_length, &signed_header);
if (result != OEMCrypto_SUCCESS) return result;
if (signed_header.buffer_size > sizeof(signed_header.buffer)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -296,8 +369,9 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyHeader(
}
/* This serializes, encrypts, and signs the specified entry into the given
* buffer. It is an error if the buffer is not big enough. The header fields in
* the entry will be updated, but the generation number will not. */
* buffer. It is an error if the buffer is not big enough. The header
* fields in the entry will be updated, but the generation number will not.
*/
NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignEntry(
SavedUsageEntry* entry, uint8_t* entry_buffer, size_t entry_buffer_length) {
entry->common_info.file_type = USAGE_TABLE_ENTRY;
@@ -325,10 +399,10 @@ NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignEntry(
return result;
}
/* This decrypts and deserializes a usage table entry from the given buffer in
* the legacy format. The signature of the buffer is verified. The generation
* number is verified by the calling function. If the buffer is not big enough
* the error OEMCrypto_ERROR_SHORT_BUFFER is returned. */
/* This decrypts and deserializes a usage table entry from the given buffer
* in the legacy format. The signature of the buffer is verified. The
* generation number is verified by the calling function. If the buffer is
* not big enough the error OEMCrypto_ERROR_SHORT_BUFFER is returned. */
NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyEntry_Legacy(
const uint8_t* entry_buffer, size_t entry_buffer_length,
SavedUsageEntry* entry) {
@@ -376,10 +450,10 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyEntry_Legacy(
return OEMCrypto_SUCCESS;
}
/* This decrypts and deserializes a usage table entry from the given buffer. The
* signature of the buffer is verified. The generation number is verified by the
* calling function. If the buffer is not big enough the error
* OEMCrypto_ERROR_SHORT_BUFFER is returned. */
/* This decrypts and deserializes a usage table entry from the given buffer.
* The signature of the buffer is verified. The generation number is
* verified by the calling function. If the buffer is not big enough the
* error OEMCrypto_ERROR_SHORT_BUFFER is returned. */
NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyEntry(
const uint8_t* entry_buffer, size_t entry_buffer_length,
SavedUsageEntry* entry) {
@@ -390,9 +464,47 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyEntry(
LOGE("Invalid entry buffer size: %zu", entry_buffer_length);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
const uint8_t* buffer = entry_buffer;
size_t buffer_length = entry_buffer_length;
SavedCommonInfo common_info;
OEMCryptoResult result = OPKI_UnpackSavedCommonInfo(
entry_buffer, entry_buffer_length, &common_info);
OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
#ifdef USE_REF_BACK_COMPAT
// To deal with reference-wrapped v16 usage tables, extract the info and
// rewrap. Then continue as usual with the rewrapped blob.
// Reference usage table doesn't have any kind of common_info struct at the
// top. Previously, fail immediatley if the common_info doesn't match
// expectations. Now, check if none of the common_info data makes sense, then
// try v16.
result = OPKI_UnpackSavedCommonInfo(buffer, buffer_length, &common_info);
if (result != OEMCrypto_SUCCESS) return result;
bool should_try_ref_compat =
(common_info.file_type != SIGNED_USAGE_TABLE_HEADER &&
common_info.file_type != SIGNED_USAGE_TABLE_ENTRY &&
common_info.file_type != USAGE_TABLE_HEADER &&
common_info.file_type != USAGE_TABLE_ENTRY);
SavedUsageEntry temp_entry = {0};
uint8_t rewrapped_entry[sizeof(SignedSavedUsageEntry)] = {0};
size_t rewrapped_entry_size = sizeof(rewrapped_entry);
if (should_try_ref_compat) {
// Unwrap into current OPK struct
result =
WTPI_RefCompat_UnwrapUsageEntry(buffer, buffer_length, &temp_entry);
if (result != OEMCrypto_SUCCESS) return result;
// Rewrap struct with current wrapping scheme
result =
EncryptAndSignEntry(&temp_entry, rewrapped_entry, rewrapped_entry_size);
if (result != OEMCrypto_SUCCESS) return result;
// Point variables to use new rewrapped data, start the process again
buffer = rewrapped_entry;
buffer_length = rewrapped_entry_size;
}
#endif
result = OPKI_UnpackSavedCommonInfo(buffer, buffer_length, &common_info);
if (result != OEMCrypto_SUCCESS) return result;
if (common_info.file_type != SIGNED_USAGE_TABLE_ENTRY) {
/* We were given the wrong file. */
@@ -402,19 +514,18 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptAndVerifyEntry(
if (common_info.format_version == LEGACY_FILE_FORMAT_VERSION) {
LOGD("Legacy usage entry format version %u detected.",
LEGACY_FILE_FORMAT_VERSION);
return DecryptAndVerifyEntry_Legacy(entry_buffer, entry_buffer_length,
entry);
return DecryptAndVerifyEntry_Legacy(buffer, buffer_length, entry);
}
if (common_info.format_version != CURRENT_FILE_FORMAT_VERSION) {
LOGE("Bad signed entry format version: %u", common_info.format_version);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (entry_buffer_length < OPKI_SignedEntrySize()) {
if (buffer_length < OPKI_SignedEntrySize()) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
SignedSavedUsageEntry signed_entry;
result = OPKI_UnpackSignedUsageEntry(entry_buffer, entry_buffer_length,
&signed_entry);
result =
OPKI_UnpackSignedUsageEntry(buffer, buffer_length, &signed_entry);
if (result != OEMCrypto_SUCCESS) return result;
if (signed_entry.buffer_size > sizeof(signed_entry.buffer)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -537,7 +648,8 @@ OEMCryptoResult OPKI_CreateUsageTableHeader(uint8_t* header_buffer,
}
*header_buffer_length = size;
if (!header_buffer) return OEMCrypto_ERROR_INVALID_CONTEXT;
/* Make sure there are no entries that are currently tied to an open session.
/* Make sure there are no entries that are currently tied to an open
* session.
*/
for (size_t i = 0; i < MAX_NUMBER_OF_USAGE_ENTRIES; i++) {
if (g_usage_table.entries[i]) {
@@ -546,8 +658,8 @@ OEMCryptoResult OPKI_CreateUsageTableHeader(uint8_t* header_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
/* Clear the table before we check the state -- we want to have an empty table
* after this function whether there was an error or not. */
/* Clear the table before we check the state -- we want to have an empty
* table after this function whether there was an error or not. */
ClearTable();
if (g_usage_table_state == USAGE_TABLE_ERROR_STATE) {
/* Something went wrong. The system should give up and re-init. */
@@ -556,11 +668,12 @@ OEMCryptoResult OPKI_CreateUsageTableHeader(uint8_t* header_buffer,
} else if (g_usage_table_state == USAGE_TABLE_ACTIVE_STATE) {
/* Creating a new header when one was already active. This is OK but
* rare. The system would do this to delete all the entries -- maybe on
* reprovisioning, but there are other reasons. However, we want to keep the
* same generation number. So we don't try to load it. */
* reprovisioning, but there are other reasons. However, we want to keep
* the same generation number. So we don't try to load it. */
} else if (g_usage_table_state ==
USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE) {
/* We are creating a brand new table. Try to load the generation number. */
/* We are creating a brand new table. Try to load the generation number.
*/
if (WTPI_LoadGenerationNumber(&g_usage_table.master_generation_number) !=
OEMCrypto_SUCCESS) {
LOGE("Failed to load generation number");
@@ -568,35 +681,38 @@ OEMCryptoResult OPKI_CreateUsageTableHeader(uint8_t* header_buffer,
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
} else {
/* Only other valid state is not initialized, which is not valid for this
* function. */
/* Only other valid state is not initialized, which is not valid for
* this function. */
LOGE("Usage table is not initialized");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
g_usage_table_state = USAGE_TABLE_ACTIVE_STATE;
g_counter_info.master_generation_number =
g_usage_table.master_generation_number;
return EncryptAndSignHeader(header_buffer, *header_buffer_length);
return EncryptAndSignHeader(header_buffer, *header_buffer_length,
&g_usage_table);
}
/* Load a usage table header. */
OEMCryptoResult OPKI_LoadUsageTableHeader(const uint8_t* buffer,
size_t buffer_length) {
/* Clear the table before we check the state -- we want to have an empty table
* before we load a new one, or we want an empty one if there is an error. */
/* Clear the table before we check the state -- we want to have an empty
* table before we load a new one, or we want an empty one if there is an
* error. */
ClearTable();
if (g_usage_table_state == USAGE_TABLE_ERROR_STATE) {
/* Something went wrong. The system should give up and re-init. */
LOGE("Usage table is in error state");
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
} else if (g_usage_table_state == USAGE_TABLE_ACTIVE_STATE) {
/* Loading a header when one was already active is an indication that the
* system was going to terminate, but changed its mind - e.g. because
* delayed termination was canceled. We keep the existing generation
* numbers. */
/* Loading a header when one was already active is an indication that
* the system was going to terminate, but changed its mind - e.g.
* because delayed termination was canceled. We keep the existing
* generation numbers. */
} else if (g_usage_table_state ==
USAGE_TABLE_INITIALIZED_BUT_NOT_LOADED_STATE) {
/* We are loading a brand new table. Try to load the generation number. */
/* We are loading a brand new table. Try to load the generation number.
*/
if (WTPI_LoadGenerationNumber(&g_usage_table.master_generation_number) !=
OEMCrypto_SUCCESS) {
LOGE("Failed to load generation number");
@@ -604,8 +720,8 @@ OEMCryptoResult OPKI_LoadUsageTableHeader(const uint8_t* buffer,
return OEMCrypto_ERROR_SYSTEM_INVALIDATED;
}
} else {
/* Only other valid state is not initialized, which is not valid for this
* function. */
/* Only other valid state is not initialized, which is not valid for
* this function. */
LOGE("Usage table is not initialized");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -621,10 +737,11 @@ OEMCryptoResult OPKI_LoadUsageTableHeader(const uint8_t* buffer,
result = OEMCrypto_WARNING_GENERATION_SKEW;
} else if (g_usage_table.master_generation_number !=
header.master_generation_number) {
/* Skew of more than 1 is an error. Clean the table and return an error. */
/* Skew of more than 1 is an error. Clean the table and return an error.
*/
ClearTable();
/* Leave the state as active, so that the generation number is kept. It is
* not a security risk to leave an empty usage header in memory. */
/* Leave the state as active, so that the generation number is kept. It
* is not a security risk to leave an empty usage header in memory. */
g_usage_table_state = USAGE_TABLE_ACTIVE_STATE;
return OEMCrypto_ERROR_GENERATION_SKEW;
}
@@ -637,10 +754,10 @@ OEMCryptoResult OPKI_LoadUsageTableHeader(const uint8_t* buffer,
return result;
}
/* Grabs a free active usage entry off of the free list of active entries. It
* updates the free list, the active_entry_map, and the session for a new
* entry. It does NOT update the entry's generation number and does NOT update
* the usage header. It does sanity checks. */
/* Grabs a free active usage entry off of the free list of active entries.
* It updates the free list, the active_entry_map, and the session for a new
* entry. It does NOT update the entry's generation number and does NOT
* update the usage header. It does sanity checks. */
NO_IGNORE_RESULT static OEMCryptoResult GrabEntry(OEMCrypto_SESSION session_id,
uint32_t usage_entry_number,
UsageEntry** entry_ptr) {
@@ -671,9 +788,9 @@ NO_IGNORE_RESULT static OEMCryptoResult GrabEntry(OEMCrypto_SESSION session_id,
return OEMCrypto_SUCCESS;
}
/** Release an active entry and put it back onto the free list. This does not
* save any data. It is usually done with the session is closing or when loading
* an entry generated an error. */
/** Release an active entry and put it back onto the free list. This does
* not save any data. It is usually done with the session is closing or when
* loading an entry generated an error. */
void OPKI_ReleaseEntry(OEMCrypto_SESSION session_id) {
if (g_usage_table_state == USAGE_TABLE_ACTIVE_STATE) {
/* Remove from active entry map. */
@@ -686,9 +803,9 @@ void OPKI_ReleaseEntry(OEMCrypto_SESSION session_id) {
}
}
/* Create a new usage entry and tie it to |session|. The new entry will have an
* entry number at the end of the array of all entries in the header, but it
* could be anywhere in the array of active entries. */
/* Create a new usage entry and tie it to |session|. The new entry will have
* an entry number at the end of the array of all entries in the header, but
* it could be anywhere in the array of active entries. */
OEMCryptoResult OPKI_CreateNewUsageEntry(OEMCrypto_SESSION session_id,
uint32_t* usage_entry_number) {
if (!usage_entry_number) {
@@ -711,8 +828,8 @@ OEMCryptoResult OPKI_CreateNewUsageEntry(OEMCrypto_SESSION session_id,
OEMCryptoResult result = GrabEntry(session_id, new_index, &entry);
if (result != OEMCrypto_SUCCESS) return result;
g_usage_table.table_size++;
/* Update the generation numbers. Increment the master GN, and then copy to
* the entry. Also copy to the header's array of entries. */
/* Update the generation numbers. Increment the master GN, and then copy
* to the entry. Also copy to the header's array of entries. */
g_usage_table.master_generation_number++;
entry->data.generation_number = g_usage_table.master_generation_number;
g_usage_table.generation_numbers[new_index] =
@@ -806,14 +923,16 @@ OEMCryptoResult OPKI_LoadUsageEntry(OEMCrypto_SESSION session_id,
OPKI_ReleaseEntry(session_id);
return result;
}
/* check generation number against header's table of generation numbers. */
/* check generation number against header's table of generation numbers.
*/
uint64_t entry_gn = entry->data.generation_number;
uint64_t header_gn = g_usage_table.generation_numbers[usage_entry_number];
if (entry_gn + 1 == header_gn || entry_gn - 1 == header_gn) {
/* Skew of 1 is a warning, but we continue on. */
result = OEMCrypto_WARNING_GENERATION_SKEW;
} else if (entry_gn != header_gn) {
/* Skew of more than 1 is an error. Clean the table and return an error. */
/* Skew of more than 1 is an error. Clean the table and return an error.
*/
OPKI_ReleaseEntry(session_id);
return OEMCrypto_ERROR_GENERATION_SKEW;
}
@@ -855,7 +974,8 @@ OEMCryptoResult OPKI_UpdateUsageEntry(OEMCrypto_SESSION session_id,
/* The new generation numbers. */
result = RollGenerationNumber(entry);
if (result != OEMCrypto_SUCCESS) return result;
result = EncryptAndSignHeader(header_buffer, *header_buffer_length);
result = EncryptAndSignHeader(header_buffer, *header_buffer_length,
&g_usage_table);
if (result != OEMCrypto_SUCCESS) return result;
result =
EncryptAndSignEntry(&entry->data, entry_buffer, *entry_buffer_length);
@@ -894,8 +1014,9 @@ OEMCryptoResult OPKI_SetUsageEntryPST(OEMCrypto_SESSION session_id,
memcpy(entry->data.pst, pst, pst_length);
entry->data.pst_length = pst_length;
/* The PST is set when the license is loaded. This will be removed in v16 when
* we use the time of license signed instead of time of license loaded. */
/* The PST is set when the license is loaded. This will be removed in v16
* when we use the time of license signed instead of time of license
* loaded. */
uint64_t now;
OEMCryptoResult result = WTPI_GetTrustedTime(&now);
if (result != OEMCrypto_SUCCESS) {
@@ -1054,8 +1175,8 @@ OEMCryptoResult OPKI_ReportUsage(OEMCrypto_SESSION session_id,
}
*buffer_length = length_needed;
// We delay checking these to allow the above length-returning code to work
// without passing in these parameters.
// We delay checking these to allow the above length-returning code to
// work without passing in these parameters.
RETURN_INVALID_CONTEXT_IF_NULL(pst);
RETURN_INVALID_CONTEXT_IF_NULL(buffer);
@@ -1215,5 +1336,6 @@ OEMCryptoResult OPKI_ShrinkUsageTableHeader(uint32_t new_entry_count,
g_usage_table.generation_numbers[i] = 0;
}
g_usage_table.table_size = new_entry_count;
return EncryptAndSignHeader(header_buffer, *header_buffer_length);
return EncryptAndSignHeader(header_buffer, *header_buffer_length,
&g_usage_table);
}

View File

@@ -3,36 +3,33 @@
Some of the headers in wtpi/ directory are tested by the code in wtpi_test/.
wtpi_test uses serialization/generator/scrape_interface.py to parse the WTPI
interface declarations and generate serialization APIs such as:
* OPK_Pack_SaveGenerationNumber_Request(),
* OPK_Unpack_K1_DeriveKeyFromKeyHandle_Response(),
* `OPK_Pack_SaveGenerationNumber_Request()`
* `OPK_Unpack_K1_DeriveKeyFromKeyHandle_Response()`
* ...
In order for the types of the parameters of these WTPI interfaces to be
correctly determined and inserted into the auto-generated
OPK_Pack_* / OPK_Unpack_* functions, certain naming conventions have to be
followed:
* To pack a variable length buffer X with type uint8_t*, the size of the
array must be named as "X_length" or XLength".
* If an output variable length buffer doesn't have an output size specified in
the parameter list, and is supposed to have the same size as the input buffer,
then the output buffer must be named as "out_buffer".
Below is an example following the naming convention above:
```
OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length,
uint8_t* out_buffer);
```
You can find more details in scrape_interface.py for what is looked for by the
parser.
OPK_Pack_* / OPK_Unpack_* functions,
[certain naming conventions][naming-conventions] have to be followed.
WTPI interfaces that are currently covered by wtpi_test:
* wtpi_generation_number_interface.h,
* wtpi_crypto_and_key_management_interface_layer1.h,
* wtpi_crypto_asymmetric_interface.h,
* wtpi_crc32_interface.h,
* wtpi_provisioning_4_interface.h,
* wtpi_generation_number_interface.h
* wtpi_crypto_and_key_management_interface_layer1.h
* wtpi_crypto_asymmetric_interface.h
* wtpi_provisioning_4_interface.h
* wtpi_crc32_interface.h
* wtpi_clock_interface_layer1.h
* wtpi_config_interface.h
* wtpi_device_key_interface.h
However, all WTPI interface may potentially be covered someday, so it's best
practice to always follow [the naming conventions][naming-conventions].
Please be cautious when updating parameter names in these interfaces. It can
potentially break the auto-generated serialization functions used by the WTPI
tests if the naming convention is not enforced.
tests if the naming conventions are not enforced. It can also cause the
generator to generate invalid or insecure code.
[naming-conventions]: https://g3doc.corp.google.com/video/widevine/g3doc/devices/oec_function_conventions.md

View File

@@ -0,0 +1,58 @@
/* Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine
License Agreement. */
#ifndef OEMCRYPTO_TA_WTPI_REF_COMPAT_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_REF_COMPAT_INTERFACE_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_serialized_usage_table.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup ref_compat
*
* This interface includes functions for backwards compatibility with 16.X
* reference wrapped blobs.
*
*
* @{
*/
/**
* Unwraps WrappedRSA struct from 16.X reference code. Returns clear RSA key.
*
*
* @param[in] wrapped_data: wrapped key
* @param[in] wrapped_data_length: length of wrapped key
* @param[out] clear_data: output for clear key
* @param[in,out] clear_data_length: size of output buffer. If it is too small
* for the output unwrapped data, this will be set to the required size.
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT NULL pointer inputs
* @retval OEMCrypto_ERROR_SHORT_BUFFER clear_data_length is too small
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
*/
OEMCryptoResult WTPI_RefCompat_UnwrapRSA(const uint8_t* wrapped_data,
size_t wrapped_data_length,
uint8_t* clear_data,
size_t* clear_data_length);
OEMCryptoResult WTPI_RefCompat_UnwrapUsageHeader(const uint8_t* wrapped_data,
size_t wrapped_data_length,
SavedUsageHeader* clear);
OEMCryptoResult WTPI_RefCompat_UnwrapUsageEntry(const uint8_t* wrapped_data,
size_t wrapped_data_length,
SavedUsageEntry* clear);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_REF_COMPAT_INTERFACE_H_ */

View File

@@ -0,0 +1,342 @@
/* Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine
License Agreement. */
#include "wtpi_ref_compat_interface.h"
#include "string.h"
#include "odk_util.h"
#include "oemcrypto_check_macros.h"
#include "oemcrypto_key_types.h"
#include "oemcrypto_serialized_usage_table.h"
#include "wtpi_device_key_access_interface.h"
#include "wtpi_device_key_interface.h"
#include "wtpi_memory_interface.h"
typedef struct {
uint8_t signature[MAC_KEY_SIZE];
uint8_t context[MAC_KEY_SIZE]; // to-be-signed data starts here
uint8_t iv[KEY_IV_SIZE];
uint8_t enc_rsa_key[]; // encrypted data starts here
} RefWrappedRSAKey;
typedef struct {
int64_t generation_number;
int64_t time_of_license_received;
int64_t time_of_first_decrypt;
int64_t time_of_last_decrypt;
enum OEMCrypto_Usage_Entry_Status status;
uint8_t mac_key_server[MAC_KEY_SIZE];
uint8_t mac_key_client[MAC_KEY_SIZE];
uint32_t index;
uint8_t pst[MAX_PST_LENGTH + 1];
uint8_t pst_length;
} RefStoredUsageEntry;
# define REF_USAGE_VERIFICATION_MAGIC_LENGTH 8
typedef struct {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH]; // to-be-signed data starts here
uint8_t verification[REF_USAGE_VERIFICATION_MAGIC_LENGTH]; // encrypted data
// starts here
RefStoredUsageEntry data;
} RefSignedEntryBlock;
typedef struct {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH]; // to-be-signed data starts here
uint8_t verification[REF_USAGE_VERIFICATION_MAGIC_LENGTH]; // encrypted data
// starts here
int64_t master_generation;
uint64_t count;
} RefSignedHeaderBlock;
OEMCryptoResult WTPI_RefCompat_UnwrapRSA(const uint8_t* wrapped_data,
size_t wrapped_data_length,
uint8_t* clear_data,
size_t* clear_data_length) {
RETURN_INVALID_CONTEXT_IF_NULL(wrapped_data);
RETURN_INVALID_CONTEXT_IF_NULL(clear_data);
RETURN_INVALID_CONTEXT_IF_NULL(clear_data_length);
if (wrapped_data_length < sizeof(RefWrappedRSAKey))
return OEMCrypto_ERROR_INVALID_CONTEXT;
if (*clear_data_length < PKCS8_DRM_KEY_MAX_SIZE)
return OEMCrypto_ERROR_INVALID_CONTEXT;
size_t rsa_key_len = wrapped_data_length - sizeof(RefWrappedRSAKey);
if (*clear_data_length < rsa_key_len) {
*clear_data_length = rsa_key_len;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
// Derive mac/enc keys from device key
const uint8_t* device_key = WTPI_GetDeviceKey();
KeySize device_key_size = WTPI_GetDeviceKeySize();
WTPI_K1_SymmetricKey_Handle device_key_handle;
OEMCryptoResult result = WTPI_K1_CreateKeyHandle(
device_key, device_key_size, DERIVING_KEY, &device_key_handle);
if (result != OEMCrypto_SUCCESS) {
return result;
}
uint8_t context[MAC_KEY_SIZE] = {0};
const RefWrappedRSAKey* const wrapped_key =
(const RefWrappedRSAKey*)wrapped_data;
memcpy(context, wrapped_key->context, sizeof(wrapped_key->context));
uint8_t empty[1] = {0};
uint8_t counter = 1;
WTPI_K1_SymmetricKey_Handle mac_server_key_handle = NULL;
WTPI_K1_SymmetricKey_Handle enc_key_handle = NULL;
result = WTPI_K1_DeriveKeyFromKeyHandle(
device_key_handle, counter, empty, 0, context, sizeof(context), empty, 0,
MAC_KEY_SERVER, MAC_KEY_SIZE, &mac_server_key_handle);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
result = WTPI_K1_DeriveKeyFromKeyHandle(
device_key_handle, counter, empty, 0, context, sizeof(context), empty, 0,
ENCRYPTION_KEY, KEY_SIZE_128, &enc_key_handle);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Use derived mac_key_server to HMAC SHA256 verify
// Verify everything after the signature
const uint8_t* data_to_verify = &(wrapped_key->context[0]);
size_t data_to_verify_length =
wrapped_data_length - sizeof(wrapped_key->signature);
result =
WTPI_C1_HMAC_SHA256_Verify(mac_server_key_handle, data_to_verify,
data_to_verify_length, wrapped_key->signature);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Use derived enc_key to AES CBC 128 decrypt
size_t data_to_decrypt_length =
wrapped_data_length - sizeof(wrapped_key->signature) -
sizeof(wrapped_key->context) - sizeof(wrapped_key->iv);
result = WTPI_C1_AESCBCDecrypt(
enc_key_handle, KEY_SIZE_128, wrapped_key->enc_rsa_key,
data_to_decrypt_length, wrapped_key->iv, clear_data);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
*clear_data_length = rsa_key_len;
cleanup:
WTPI_K1_FreeKeyHandle(device_key_handle);
WTPI_K1_FreeKeyHandle(mac_server_key_handle);
WTPI_K1_FreeKeyHandle(enc_key_handle);
return result;
}
OEMCryptoResult WTPI_RefCompat_UnwrapUsageHeader(const uint8_t* wrapped_data,
size_t wrapped_data_length,
SavedUsageHeader* clear) {
RETURN_INVALID_CONTEXT_IF_NULL(wrapped_data);
RETURN_INVALID_CONTEXT_IF_NULL(clear);
if (wrapped_data_length < sizeof(RefSignedHeaderBlock)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// RefSignedHeaderBlock has two issues that make things inconvenient
// 1. Doesn't include generation number array
// 2. Has a uint64_t which makes alignement 8, so we can't directly cast the
// uint8_t* pointer to RefSignedHeaderBlock*
uint8_t clear_data[sizeof(RefSignedHeaderBlock) +
MAX_NUMBER_OF_USAGE_ENTRIES * sizeof(uint64_t)] = {0};
RefSignedHeaderBlock* clear_header = (RefSignedHeaderBlock*)clear_data;
const uint8_t* wrapped_sig = wrapped_data;
const uint8_t* wrapped_iv = &wrapped_data[sizeof(clear_header->signature)];
const uint8_t* wrapped_enc =
&wrapped_data[sizeof(clear_header->signature) + sizeof(clear_header->iv)];
memcpy(clear_header->signature, wrapped_sig, sizeof(clear_header->signature));
memcpy(clear_header->iv, wrapped_iv, sizeof(clear_header->iv));
// Get device key
const uint8_t* device_key = WTPI_GetDeviceKey();
KeySize device_key_size = WTPI_GetDeviceKeySize();
WTPI_K1_SymmetricKey_Handle device_key_handle;
OEMCryptoResult result = WTPI_K1_CreateKeyHandle(
device_key, device_key_size, DERIVING_KEY, &device_key_handle);
if (result != OEMCrypto_SUCCESS) {
return result;
}
// HMAC verify with key. Data starts at buffer->iv (after buffer->signature)
// and goes to end. Compare with buffer->signature
result = WTPI_C1_HMAC_SHA256_Verify(
device_key_handle, wrapped_iv,
wrapped_data_length - sizeof(clear_header->signature), wrapped_sig);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Decrypt AES
const size_t encrypted_length = wrapped_data_length -
sizeof(clear_header->signature) -
sizeof(clear_header->iv);
result = WTPI_C1_AESCBCDecrypt(device_key_handle, device_key_size,
wrapped_enc, encrypted_length, wrapped_iv,
clear_header->verification);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Compare verification string
const char* kHeaderVerification = "USEHEADR";
if (crypto_memcmp(kHeaderVerification, clear_header->verification,
sizeof(clear_header->verification)) != 0) {
result = OEMCrypto_ERROR_INVALID_CONTEXT;
goto cleanup;
}
// Move everything to newer "SavedUsageHeader" struct
*clear = (SavedUsageHeader){
.common_info =
{
.file_type = USAGE_TABLE_HEADER,
.format_version = CURRENT_FILE_FORMAT_VERSION,
},
.master_generation_number = clear_header->master_generation,
.table_size =
clear_header->count & 0xFFFFFFFF, // intentionally truncating count
};
memcpy(clear->generation_numbers, &clear_data[sizeof(RefSignedHeaderBlock)],
clear_header->count * sizeof(uint64_t));
cleanup:
WTPI_K1_FreeKeyHandle(device_key_handle);
return result;
}
OEMCryptoResult WTPI_RefCompat_UnwrapUsageEntry(const uint8_t* wrapped_data,
size_t wrapped_data_length,
SavedUsageEntry* clear) {
RETURN_INVALID_CONTEXT_IF_NULL(wrapped_data);
RETURN_INVALID_CONTEXT_IF_NULL(clear);
if (wrapped_data_length < sizeof(RefSignedEntryBlock)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t clear_data[sizeof(RefSignedEntryBlock)] = {0};
RefSignedEntryBlock* clear_entry = (RefSignedEntryBlock*)clear_data;
const uint8_t* wrapped_sig = wrapped_data;
const uint8_t* wrapped_iv = &wrapped_data[sizeof(clear_entry->signature)];
const uint8_t* wrapped_enc =
&wrapped_data[sizeof(clear_entry->signature) + sizeof(clear_entry->iv)];
memcpy(clear_entry->signature, wrapped_sig, sizeof(clear_entry->signature));
memcpy(clear_entry->iv, wrapped_iv, sizeof(clear_entry->iv));
// Get device key
const uint8_t* device_key = WTPI_GetDeviceKey();
KeySize device_key_size = WTPI_GetDeviceKeySize();
WTPI_K1_SymmetricKey_Handle device_key_handle;
OEMCryptoResult result = WTPI_K1_CreateKeyHandle(
device_key, device_key_size, DERIVING_KEY, &device_key_handle);
if (result != OEMCrypto_SUCCESS) {
return result;
}
// HMAC verify with key. Data starts at buffer[SHA256_DIGEST_LENGTH] and goes
// to end Compare with first SHA256_DIGEST_LENGTH bytes
result = WTPI_C1_HMAC_SHA256_Verify(
device_key_handle, wrapped_iv,
wrapped_data_length - sizeof(clear_entry->signature), wrapped_sig);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Decrypt AES
const size_t encrypted_length = wrapped_data_length -
sizeof(clear_entry->signature) -
sizeof(clear_entry->iv);
result = WTPI_C1_AESCBCDecrypt(device_key_handle, device_key_size,
wrapped_enc, encrypted_length, wrapped_iv,
clear_entry->verification);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
// Compare verification string
const char* kentryVerification = "USEENTRY";
if (crypto_memcmp(kentryVerification, clear_entry->verification,
sizeof(clear_entry->verification)) != 0) {
result = OEMCrypto_ERROR_INVALID_CONTEXT;
goto cleanup;
}
// Copy values to new struct
*clear = (SavedUsageEntry){
.common_info =
{
.file_type = USAGE_TABLE_ENTRY,
.format_version = CURRENT_FILE_FORMAT_VERSION,
},
.index = clear_entry->data.index,
.generation_number = clear_entry->data.generation_number,
.time_of_license_received = clear_entry->data.time_of_license_received,
.time_of_first_decrypt = clear_entry->data.time_of_first_decrypt,
.time_of_last_decrypt = clear_entry->data.time_of_last_decrypt,
.status = clear_entry->data.status,
.pst_length = clear_entry->data.pst_length,
};
memcpy(clear->pst, clear_entry->data.pst, sizeof(clear->pst));
// MAC keys need to be wrapped for OPK
WTPI_K1_SymmetricKey_Handle mac_server_key_handle;
result = WTPI_K1_CreateKeyHandle(clear_entry->data.mac_key_server,
sizeof(clear_entry->data.mac_key_server),
MAC_KEY_SERVER, &mac_server_key_handle);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
result = WTPI_K1_WrapKey(DEVICE_KEY_WRAP_MAC_KEY, mac_server_key_handle,
MAC_KEY_SERVER, clear->mac_key_server,
WRAPPED_MAC_KEY_SIZE);
WTPI_K1_FreeKeyHandle(mac_server_key_handle);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to wrap mac key server");
goto cleanup;
}
WTPI_K1_SymmetricKey_Handle mac_client_key_handle;
result = WTPI_K1_CreateKeyHandle(clear_entry->data.mac_key_client,
sizeof(clear_entry->data.mac_key_client),
MAC_KEY_CLIENT, &mac_client_key_handle);
if (result != OEMCrypto_SUCCESS) {
goto cleanup;
}
result = WTPI_K1_WrapKey(DEVICE_KEY_WRAP_MAC_KEY, mac_client_key_handle,
MAC_KEY_CLIENT, clear->mac_key_client,
WRAPPED_MAC_KEY_SIZE);
WTPI_K1_FreeKeyHandle(mac_client_key_handle);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to wrap mac key client");
goto cleanup;
}
cleanup:
WTPI_K1_FreeKeyHandle(device_key_handle);
return result;
}

View File

@@ -87,6 +87,7 @@ void print_cbor(cn_cbor* cn, uint32_t type) {
}
namespace wtpi_test {
namespace {
// Copied and modified from open-dice test_utils.cc
ScopedCbor ExtractCwtFromCborCertificate(const uint8_t* certificate,
size_t certificate_size) {
@@ -157,6 +158,7 @@ ScopedCbor ExtractPublicKeyFromCwt(const cn_cbor* cwt) {
}
return key;
}
} // namespace
ScopedCbor ExtractPublicKeyFromBcc(const uint8_t* bytes, size_t bytes_len) {
// Get bcc payload, which is a CBOR Web Token.

View File

@@ -16,6 +16,8 @@
#include "wtpi_device_key_interface.h"
#define UUID_LENGTH 16
namespace {
// This struct represents a wrapped blob that we do not yet know how to
// interpret. It contains only the fields that we expect every versioned blob to
// have.
@@ -27,11 +29,11 @@ typedef struct WrappedData {
} WrappedData;
// The randomly-generated UUID that identifies a blob as a WrappedData struct,
// in network byte order.
static const uint8_t kMagicUuid[UUID_LENGTH] = {
0xb5, 0x76, 0x3b, 0xad, 0x84, 0x05, 0x40, 0xfd,
0xa0, 0x88, 0x3b, 0x6c, 0x69, 0x97, 0xfc, 0x74};
const uint8_t kMagicUuid[UUID_LENGTH] = {0xb5, 0x76, 0x3b, 0xad, 0x84, 0x05,
0x40, 0xfd, 0xa0, 0x88, 0x3b, 0x6c,
0x69, 0x97, 0xfc, 0x74};
// 1 in network byte order
static const uint8_t kVersionOne[sizeof(uint32_t)] = {0x00, 0x00, 0x00, 0x01};
const uint8_t kVersionOne[sizeof(uint32_t)] = {0x00, 0x00, 0x00, 0x01};
// This is the layout of the |data| field of a WrappedData structure when its
// |version| field is 1.
typedef struct WrappedData_V1 {
@@ -39,15 +41,15 @@ typedef struct WrappedData_V1 {
uint8_t enc_data[];
} WrappedData_V1;
static OEMCryptoResult GetEncryptAndSignSize(uint32_t context, size_t in_size,
size_t* wrapped_size) {
OEMCryptoResult GetEncryptAndSignSize(uint32_t context, size_t in_size,
size_t* wrapped_size) {
*wrapped_size = in_size + sizeof(WrappedData) + sizeof(WrappedData_V1);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult EncryptAndSign_V1(uint32_t context, const uint8_t* data,
size_t data_size, uint8_t* out,
size_t* out_size) {
size_t data_size, uint8_t* out,
size_t* out_size) {
if (!out_size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -91,6 +93,7 @@ OEMCryptoResult EncryptAndSign_V1(uint32_t context, const uint8_t* data,
WTPI_K1_FreeKeyHandle(signing_key);
return result;
}
} // namespace
class LegacyKeywrapTest : public ::testing::Test {
protected:

View File

@@ -7,6 +7,7 @@
#include "log.h"
namespace {
void dump_ssl_error(void) {
int count = 0;
unsigned long err;
@@ -17,6 +18,7 @@ void dump_ssl_error(void) {
LOGE("SSL Error %d -- %lu -- %s", count, err, buffer);
}
}
} // namespace
bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size,
RSA** rsa) {

View File

@@ -12,7 +12,10 @@
* This is a PKCS8 RSA key encoded in DER format.
*/
#include "stdint.h"
#include "test_common.h"
#include <stdint.h>
uint8_t test_rsa_key_der[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,

View File

@@ -9,6 +9,8 @@
// posix_services.h implementation of semaphores and shared memory
// which is based on the POSIX shared memory and semaphore libraries.
#include "tos_transport.h"
#include "odk_message.h"
#include "posix_resources.h"
#include "tos_transport_interface.h"
@@ -20,19 +22,20 @@
using namespace posix;
namespace {
// message request/response payload data
static RequestResponseBlock* shared_memory_ = nullptr;
RequestResponseBlock* shared_memory_ = nullptr;
// mailbox containing the size of the payload
static MailboxBlock* mailbox_memory_ = nullptr;
MailboxBlock* mailbox_memory_ = nullptr;
// post when a request message is ready
static RequestSemaphore* request_semaphore_ = nullptr;
RequestSemaphore* request_semaphore_ = nullptr;
// post when a response message is ready
static ResponseSemaphore* response_semaphore_ = nullptr;
ResponseSemaphore* response_semaphore_ = nullptr;
static void ReleaseResources() {
void ReleaseResources() {
if (shared_memory_) {
delete shared_memory_;
shared_memory_ = nullptr;
@@ -51,6 +54,25 @@ static void ReleaseResources() {
}
}
// Get the size of the message from the mailbox and return it
uint32_t PeekSize(void) {
uint8_t* mailbox = mailbox_memory_->GetAddress();
uint32_t message_size = (uint32_t)mailbox[0] | (uint32_t)mailbox[1] << 8 |
(uint32_t)mailbox[2] << 16 |
(uint32_t)mailbox[3] << 24;
return message_size;
}
// Put the size of the message into the mailbox
void PokeSize(uint32_t size) {
uint8_t* mailbox = mailbox_memory_->GetAddress();
mailbox[0] = (uint8_t)(size);
mailbox[1] = (uint8_t)(size >> 8);
mailbox[2] = (uint8_t)(size >> 16);
mailbox[3] = (uint8_t)(size >> 24);
}
} // namespace
bool TOS_Transport_Initialize(void) {
if (!(shared_memory_ = new RequestResponseBlock()) ||
!(shared_memory_->Allocate(OPK_TRANSPORT_MESSAGE_SIZE))) {
@@ -94,24 +116,6 @@ void TOS_Transport_ReleaseMessage(ODK_Message* message) {
(void)message;
}
// Get the size of the message from the mailbox and return it
static uint32_t PeekSize(void) {
uint8_t* mailbox = mailbox_memory_->GetAddress();
uint32_t message_size = (uint32_t)mailbox[0] | (uint32_t)mailbox[1] << 8 |
(uint32_t)mailbox[2] << 16 |
(uint32_t)mailbox[3] << 24;
return message_size;
}
// Put the size of the message into the mailbox
static void PokeSize(uint32_t size) {
uint8_t* mailbox = mailbox_memory_->GetAddress();
mailbox[0] = (uint8_t)(size);
mailbox[1] = (uint8_t)(size >> 8);
mailbox[2] = (uint8_t)(size >> 16);
mailbox[3] = (uint8_t)(size >> 24);
}
// The request has been packed into the shared memory, all we need to
// do is poke the message size in the mailbox and post on the request
// semaphore, then wait for the response semaphore. The response will

View File

@@ -0,0 +1,39 @@
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
#include "oemcrypto_ref_compat_test.h"
#include "bcc_validator.h"
#include "device_info_validator.h"
#include "log.h"
#include "oec_device_features.h"
#include "platform.h"
#include "signed_csr_payload_validator.h"
#include "test_sleep.h"
namespace wvoec {
TEST_F(OEMCryptoProv2ReferenceWrap, LoadWrappedKey) {
OEMCryptoResult sts = OEMCrypto_ERROR_INVALID_CONTEXT;
sts = OEMCrypto_LoadDRMPrivateKey(
session_.session_id(), OEMCrypto_RSA_Private_Key, wrapped_rsa_key.data(),
wrapped_rsa_key.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
TEST_F(OEMCryptoProv2ReferenceWrap, LoadWrappedUsageTable) {
OEMCryptoResult sts = OEMCrypto_ERROR_INVALID_CONTEXT;
sts = OEMCrypto_LoadUsageTableHeader(wrapped_usage_header.data(),
wrapped_usage_header.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
sts = OEMCrypto_LoadUsageEntry(session_.session_id(), 0,
wrapped_usage_entry.data(),
wrapped_usage_entry.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
} // namespace wvoec

View File

@@ -0,0 +1,203 @@
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Test data generated by v16.3 reference code for wrapped RSA keys and wrapped
// usage tables. Used to test optional support in OPK to unwrap legacy formats.
//
#ifndef CDM_OEMCRYPTO_REFERENCE_COMPATIBILITY_TEST_
#define CDM_OEMCRYPTO_REFERENCE_COMPATIBILITY_TEST_
#include <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "oec_extra_test_keys.h"
#include "oemcrypto_basic_test.h"
#include "oemcrypto_license_test.h"
#include "oemcrypto_resource_test.h"
namespace wvoec {
/* The uncommented test data below was created with certain device qualities
from the reference, which should be matched in the OPK in order to pass tests.
All of these qualities should be covered in the below comments. Most notably:
1. device key is 0xE4FF574C322EF53426212CB3ED37F35E. This comes from the 7912
test keybox.
2. generation number loaded from file is 0x601839158FACD420
*/
// RSA key
// std::vector<uint8_t> master_key =
// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E");
// std::vector<uint8_t> mac_key_context = wvutil::a2b_hex(
// "2A20B95C28A52646C7192489DC9CF12257E1EB3B929D6B7D699F598BB87C4D4A");
// std::vector<uint8_t> enc_key_context = wvutil::a2b_hex(
// "2A20B95C28A52646C7192489DC9CF12257E1EB3B929D6B7D699F598BB87C4D4A");
// std::vector<uint8_t> mac_key_server = wvutil::a2b_hex(
// "6A98FB80AC7A91C7F25D5A38C8748EA85B2E390B2AEA65E5DBC06DFC8402923A");
// std::vector<uint8_t> mac_key_client = wvutil::a2b_hex(
// "BE5CE5801E1EA7FF235951570603CFFB4C405662EA1D641D959CC6F14431C32F");
// std::vector<uint8_t> enc_key =
// wvutil::a2b_hex("6A98FB80AC7A91C7F25D5A38C8748EA8");
// std::vector<uint8_t> enc_rsa_key_iv =
// wvutil::a2b_hex("AE32578914AC408D00AB0156F38214CD");
// std::vector<uint8_t> signature = wvutil::a2b_hex(
// "5173F3B523AA4DE5E5FE7D26E2913EAB0A312224D0C84B6C903E869764553555");
std::vector<uint8_t> clear_rsa_key = wvutil::a2b_hex(
"5349474E00000002308204BC020100300D06092A864886F70D01010105000482"
"04A6308204A20201000282010100A700366065DCBD545A2A40B4E1159458114F"
"9458DDDEA71F3C2CE08809296157675E567EEE278F59349A2AAA9DB44EFAA76A"
"D4C97A53C14E9FE334F73DB7C910474F28DA3FCE317BFD0610EBF7BE92F9AFFB"
"3E68DAEE1A644CF329F2739E39D8F66FD8B28082718EB5A4F2C23ECD0ACAB604"
"CD9A138B54735425548CBE987A67ADDAB34EB3FA82A84A679856575471CD127F"
"EDA301C06A8B24039688BE97662ABC53C98306515A88651318E43AED6BF1615B"
"4CC81EF4C2AE085E2D5FF8127FA2FCBB211830DAFE40FB01CA2E370ECEDD7687"
"82460B3A778FC072072C7F9D1E865BED2729DF039762EF44D35B3DDB9C5E1B7B"
"39B40B6D046BBBBB2C5FCFB37A050203010001028201005E796549A57679F905"
"450FF403BDA47D29D5DE3363D8B8AC97EB3F5E55E87DF3E73B5C2D546736D61D"
"46F5CA2D8B3A7EDC4538797E65715F1C5E79B140CDFEC5E1C16B78044E8E79F9"
"0AFC79B15EB360E3687BC6EFCB714CBAA7795C7A81D171E7002113E255690E75"
"BE09C34FA9C968220E978D896EF1E8887AD1D9095DD32878250B1C477325CC21"
"B6DAC6245AD0371446C79469E4436F47DE00334D8F9572FA68711766121A8727"
"F7EF7EE03558F24D6F3501AA96E23D5113869C79D0B7B664E8866550BFCC2753"
"1F51D4CABEF5DD7770980FEEA896075F456A7A0D039C4F29F606F35D586C47D0"
"96A90317BB4EC921E0ACCD7878B2FE81B25153A61F984502818100CF738CBE6D"
"452D0C0B5D5C6C7578CC3548B698F1B964608C43EB85AB04B67D1B717506E2DA"
"84682E7F4CE373B4DE514BB651867BD0E64DF3D1CF1AFE7F3A83BAB3E1FF5413"
"93D79C2780B71E649EF7322B4629F7F8186CF74ABE4BEE96908FA216226ACC48"
"067463437F2722443C2D3B62F11CB427338526604816CBEFF8CD3702818100CE"
"15436E4B0FF93F87C3414597B149C2192387E4241C64E528CB431014140E19CB"
"BBDBFD119D1768786D6170633AA1B3F3A75B0EFFB76111549199E591322DEB3F"
"D83EF7D4CBD2A341C1EEC69213EB7F4258F4D0B2741D8E8746CD14B816ADB5BD"
"0D6C955A16BFE953DAFBED835167A955AB54029520A6681753A8EA43E5B0A302"
"8180679C32833957FF73B089648BD6F00A2DE2AF301C2A97F3909AAB9B0B1B43"
"79A0A73DE7BE8D9CEBDBAD40DDA90080B8E1B3A16C2592E433B2BEEB4D74265F"
"37439C6C17760A812082A1482C2D45DC0F624332BBEB5941F9CA58CE4A665354"
"C828101E087116D802714158D456CCF5B131A3ED008509BF3595412940198335"
"246902818055100BCC3BA9753D16E1AE50766394494CAD10CB47687CF0E5DCB8"
"6AAB8EF79F082C1B8AA2B98FCEEC5E61A8CD1C87604AC31A5FDF8726C6CB7C69"
"E48B01065922FA344B81873C036D020A77E615D8CFA768266CFA2BD9835A2D0C"
"3B701CD448BEA70AD9BEDCC30C2133B366FF1C1BC89676E86F4474BC9B1C7DC8"
"AC21A86E370281802C7CAD1E75F6691DE7A6CA747D67C8652866C443A6BD4057"
"AEB7652C52F9E4C7817B56A3D20DE83370CF0684B34E4450756196864BB62BAD"
"F0AD57D0370D1D3550CB69223929B93AD329230260F7AB3040DA8E4D457026F4"
"A20DD0645D473C18F4D4529500AE846B47B23C82D37253DE722CF7C12236D918"
"56FE392833E0DB030808080808080808");
std::vector<uint8_t> wrapped_rsa_key = wvutil::a2b_hex(
"5173F3B523AA4DE5E5FE7D26E2913EAB0A312224D0C84B6C903E869764553555"
"2A20B95C28A52646C7192489DC9CF12257E1EB3B929D6B7D699F598BB87C4D4A"
"AE32578914AC408D00AB0156F38214CDD920B0EC5083C3916445A6FBC7D74786"
"6181E9B06C761D94DC6DD07FE1FA4BB691F71791AF0530A193E312AB89ACB62C"
"07312E07326BE72BC9368CDD20929E3D779486602AF40E3749C8C89E06018986"
"E4CE4A84907561FFE2D25C20B3E7F7A31DD548D220A17D1BC0F5E92E47DA5E51"
"6B3EA63BCCB4764C4B4CE0DD5B712A0D0161B035ADEE0D78A93BDE3B1ADDB2A4"
"46A57D40BDEAA9FF5ADBDF40C17FC40A269E3A0EF435A0E0C416DC9D946DDF56"
"75197B132BCE0D3D433F1B32F66AC35379861555F733CED6D5BDF145DA7975D4"
"AA40DCB44CB6677E1C896AB69EFB6DC43972D9B93E3E9F7DE46A05A4083646C8"
"AD228FFC3FE38335F32B6CDA2A99E98B7F66E1E175F4AB2E07C696CA50D40922"
"4AD46697D669FD40DFD67C08016CE68FC18BD3E6F23903D7A5B780DC74DC13F3"
"AEE716F78A5A2D11546C37680D391D4FB4EB094B1AC70E0950AD65FE7598A622"
"F4C50B18B72CC8E26FB3D6BA87C732C5705E102A92D3DFC7F7D57F16448E1EE0"
"C696FE8E05239EBBC7C6951374EA04BFB76F49BED4B3A04C38C9C91E2218C7EE"
"2D9E1B4ED37A3907395380A8400CDBBDE7E6BFF4ED4F0BED3D839A26707B6CA9"
"262F4DE1905B34B50C878EF6860A2E649E2960C0860A0B09E5DC22692EC0A4AA"
"0E247A2DB168C1BC979128F29E54F268E0E3CC5A0231838B76A61C97779E5D7A"
"2955D33498537878FAC36623A3099EDDB04B0AE748563AB2AC0C0614D776437F"
"E9F7C0D149196EF5CB15BE496CE8DC004F0AF79FADB5FB33677CA350A6999367"
"535404D9417BED0E794CED1251A9C2F5170DEAF8B0A4EAE8CD5CA3E65E7F5087"
"441DFCF48CBC97D6C89A39BFEAC0F45AD8D2977EE04E3B0AC5EF61303361DF05"
"E182A0C3BF0B1CB7C7DDA499CE2E10904DEE0BC58F6F8A6D1BEE3A389C5308D2"
"0AAFD655A6003914BA5A00ED3BCEC64DE21033BE8E01F0594D1C2899609FDA23"
"89DD4F77873C39C9D51C6A8F4967734F68A793EE6F167BCCE66F96473CBDD2E5"
"2D0A85124468C260D0F0E1C87C85F32B6443346550DAB72FDCA727BC9C725BA4"
"E3A87522C42BE4C2622F90F47A0E344E9C5CE0D9427211834DA4ABDFBDFB0B7C"
"8DF7A9DBFB3606DE7053FB28EDC4ED3074F08308F9F77BF983D798E0AFCA2761"
"9D12522A1E7346A40A30C0785EE1C271FC40E611FCF6AD633B34F729DFFDB2E0"
"ABBF04CC0B5D564351006855BDDCAE20BA4240AF6599949A41F3FF461358D215"
"C81CCA82BF89DE581C1F29EA083FE5C8CAEE53237AF872D78086B3219E134369"
"372A02EA7640A1DCF7FE82AFE8F43376CA2B3374BA78CBE63CA34D1D5F4EDBEA"
"045311A1BD28D10F1346F72DFAF81C33CA6417D666102CE0A9EE0277F077633D"
"6A3FE5206E8D4A61869417532C219C4F9C1311FF18708893F365D612AFC3A19A"
"98D1A25E058AB03FA6DED49165352E8CE268790A8343CAE9FAE33090078A9475"
"7589F369E559A303EE637725DB73FECC38754764BE37018A21A083FB509F4078"
"3F3A2F5116343320865BAF15F2020FBDC073BC9A92EAA2A2ECE315F22D3FD15B"
"E2303324769ED52511C8DED664C5657A8DAD823DD7EC80B1DF8427AF5D211620"
"6D9A31DFEA34A867B81A6BBBBEF04ED9C1B1E9FDDEB5EE6CF42EAAC6794609A9"
"BC5AB70CC4891D984DBC7210A1016FBB68B6222213D5F6D011A8309A15A5B04E"
"5C0131463D899324091E951252FD6DE232E38816478E227ABFBED403900D18F9");
// Usage entry
// std::vector<uint8_t> key =
// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E"); std::vector<uint8_t>
// iv_buffer = wvutil::a2b_hex("B8D3247322351E0A4E06BB5E0BD87151");
// std::vector<uint8_t> signature =
// wvutil::a2b_hex("333F3815A67D92F91BF8E31479DEC4C19897059C12B6D4F10BA1CA886382DE75");
std::vector<uint8_t> clear_usage_entry = wvutil::a2b_hex(
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"555345454E5452591FD4AC8F1539186007EE7C66000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000");
std::vector<uint8_t> wrapped_usage_entry = wvutil::a2b_hex(
"333F3815A67D92F91BF8E31479DEC4C19897059C12B6D4F10BA1CA886382DE75"
"FA8917E41699C6A7BCD2D2F9F63F85E700000000000000000000000000000000"
"EE26BDE360B7C505D65A3B83384B9AACD9F64E6BB05135291AD6D337C2682C34"
"F8B5727BF1AB93E3E905D247B9E1717944547D6598723EE3B5BFBC0B0E6F9465"
"65FEC2E3869CC5878D9C0F44D72B6E2F967C9AFB4A2AA78D03B90993F7C1F80D"
"35A85BF48D625F315FE71270E6E04D586E7954FA6DB4B818962FEECEE317C0EB"
"5D29778EB125B2886AE0BDD0049BB5EB5C202C939DA0DF5B65BFEB5CB9690FE6"
"C4757A41E51F08CE9839F960B9DC71013C611A46A374A1500B5D02206A183A2A"
"0EFE55AB3FE3F5FA353F1E9E75F747A6A81291C71D6F1DEBAB55A76A05564A32"
"B28A538872CEC35F8BE21313DE0BCB309EB49B4300CA95249169033AEDA72ED2"
"54368DB0F434ACCBC958D06043800F0515CC0C618C5D54FE4804984985189450"
"FE9B105FC3605838B624CC5602FB93FC668B34DF3F6D754CC6D57DD08DB3614F"
"194A889CD9101A22D001F87D79DF8680F72FFEA213B1927FEC3A1E04C82F4A72"
"749718B3423DD3D040AD50D5AFCBCA85B8D3247322351E0A4E06BB5E0BD87151");
// Usage header
// std::vector<uint8_t> key =
// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E"); std::vector<uint8_t>
// iv_buffer = wvutil::a2b_hex("CBD0C898BFC17A6D8455F1F3F746F4FE");
// std::vector<uint8_t> signature =
// wvutil::a2b_hex("DC6E448F7AC3A43F423310FAF0818A3C73BD067B4414707D8E0656F6CCDFF4AC");
// std::vector<uint8_t> master_generation_number =
// wvutil::a2b_hex("601839158FACD420")
std::vector<uint8_t> clear_usage_header = wvutil::a2b_hex(
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"555345484541445220D4AC8F1539186001000000000000001FD4AC8F15391860");
std::vector<uint8_t> wrapped_usage_header = wvutil::a2b_hex(
"DC6E448F7AC3A43F423310FAF0818A3C73BD067B4414707D8E0656F6CCDFF4AC"
"60E0A2725D56A0C93EE5067F1BDF8EB100000000000000000000000000000000"
"C0847CFCB2AE7DAD634578FBF07870F9CBD0C898BFC17A6D8455F1F3F746F4FE");
class OEMCryptoProv2ReferenceWrap : public OEMCryptoClientTest {
protected:
void SetUp() override {
OEMCryptoClientTest::SetUp();
ASSERT_NO_FATAL_FAILURE(session_.open());
if (global_features.provisioning_method != OEMCrypto_Keybox) {
GTEST_SKIP() << "Test for prov 2 devices only";
}
}
void TearDown() override {
ASSERT_NO_FATAL_FAILURE(session_.close());
OEMCryptoClientTest::TearDown();
}
Session session_;
};
} // namespace wvoec
#endif // CDM_OEMCRYPTO_REFERENCE_COMPATIBILITY_TEST_

View File

@@ -52,6 +52,7 @@ cflags_c += \
cppflags += \
$(cflags) \
-std=c++14 \
$(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++14)
endef
# Generate rules to run clang-tidy with each source file.

View File

@@ -19,6 +19,7 @@
static pthread_t main_thread_tid;
static bool thread_running = false;
namespace {
void signalHandler(int signum) {
(void)signum;
// TODO(fredgc): this doesn't actually kill anything because the main loop is
@@ -27,6 +28,7 @@ void signalHandler(int signum) {
// This exits, but then we skip the OPK_Terminate call.
exit(0);
}
} // namespace
// The request message data must be copied into a local buffer
// so the contents can't be modified while being parsed.

View File

@@ -9,7 +9,9 @@
#include "oemcrypto_corpus_generator_helper.h"
#include "test_sleep.h"
static void acknowledge_cast() {
namespace {
void acknowledge_cast() {
std::cout
<< "==================================================================\n"
<< "= This device is expected to load x509 certs as a cast receiver. =\n"
@@ -38,6 +40,8 @@ int CheckAndInstallProv30ROT() {
return 0;
}
} // namespace
// This special main procedure is used instead of the standard GTest main,
// because we need to initialize the list of features supported by the device.
// Also, the test filter is updated based on the feature list.

View File

@@ -52,6 +52,7 @@ cflags_c += \
cppflags += \
$(cflags) \
-std=c++14 \
$(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++14)
endef
# Generate rules to run clang-tidy with each source file.

View File

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

View File

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

View File

@@ -52,6 +52,6 @@ UBSAN_IGNORE_UNSIGNED_OVERFLOW void* OPK_BumpAllocate(size_t nbytes) {
void OPK_BumpAllocator_Reset(void) {
LOGV("bump allocator capacity = %d", BUFFER_SIZE);
memset(buffer, 0, BUFFER_SIZE);
memset(buffer, 0, buffer_offset);
buffer_offset = 0;
}

View File

@@ -122,7 +122,7 @@ void OPK_SharedBuffer_Terminate(void) {
* allocated.
*/
void OPK_SharedBuffer_Reset(void) {
memset(&allocations_[0], 0, sizeof(allocations_));
memset(&allocations_[0], 0, buffer_count_ * sizeof(allocations_[0]));
next_buffer_offset_ = 0;
next_buffer_index_ = 0;
buffer_count_ = 0;

View File

@@ -1,27 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
vendor/widevine/libwvdrmengine/cdm/util/include \
LOCAL_MODULE:=oemcrypto_test
LOCAL_LICENSE_KINDS:=legacy_by_exception_only legacy_proprietary
LOCAL_LICENSE_CONDITIONS:=by_exception_only proprietary by_exception_only
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_OWNER := widevine
LOCAL_PROPRIETARY_MODULE := true
LOCAL_C_INCLUDES += external/googletest/googlemock/include \
# When built, explicitly put it in the DATA/nativetest directory.
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
ifneq ($(TARGET_ENABLE_MEDIADRM_64), true)
LOCAL_MODULE_TARGET_ARCH := arm x86 mips
endif
include $(LOCAL_PATH)/common.mk
include $(BUILD_EXECUTABLE)

View File

@@ -1,70 +0,0 @@
LOCAL_PATH:= $(call my-dir)
ifeq ($(filter mips mips64, $(TARGET_ARCH)),)
# Tests need to be compatible with devices that do not support gnu hash-style
LOCAL_LDFLAGS+=-Wl,--hash-style=both
endif
# The unit tests can access v15 functions through the dynamic adapter:
LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15
LOCAL_SRC_FILES:= \
GEN_api_lock_file.c \
oec_device_features.cpp \
oec_decrypt_fallback_chain.cpp \
oec_key_deriver.cpp \
oec_session_util.cpp \
oemcrypto_corpus_generator_helper.cpp \
oemcrypto_session_tests_helper.cpp \
oemcrypto_basic_test.cpp \
oemcrypto_cast_test.cpp \
oemcrypto_decrypt_test.cpp \
oemcrypto_generic_crypto_test.cpp \
oemcrypto_license_test.cpp \
oemcrypto_provisioning_test.cpp \
oemcrypto_security_test.cpp \
oemcrypto_usage_table_test.cpp \
oemcrypto_test.cpp \
oemcrypto_test_android.cpp \
oemcrypto_test_main.cpp \
ota_keybox_test.cpp \
../../cdm/util/test/test_sleep.cpp \
../util/src/oemcrypto_ecc_key.cpp \
../util/src/oemcrypto_rsa_key.cpp \
../util/src/wvcrc.cpp \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/fuzz_tests \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../odk/include \
$(LOCAL_PATH)/../odk/kdo/include \
$(LOCAL_PATH)/../ref/src \
$(LOCAL_PATH)/../util/include \
vendor/widevine/libwvdrmengine/cdm/core/include \
vendor/widevine/libwvdrmengine/cdm/util/include \
vendor/widevine/libwvdrmengine/cdm/util/test \
LOCAL_STATIC_LIBRARIES := \
libcdm \
libcppbor \
libjsmn \
libgmock \
libgtest \
libgtest_main \
libwvlevel3 \
libcdm_protos \
libcdm_utils \
libwv_kdo \
libwv_odk \
LOCAL_SHARED_LIBRARIES := \
libbase \
libcrypto \
libdl \
libbinder_ndk \
liblog \
libmedia_omx \
libprotobuf-cpp-lite \
libstagefright_foundation \
libutils \
libz \

View File

@@ -42,12 +42,8 @@
{
'target_name': 'oemcrypto_opk_dispatcher_fuzz',
'include_dirs': [
'<(oemcrypto_dir)/opk/serialization/common',
'<(oemcrypto_dir)/opk/serialization/common/include',
'<(oemcrypto_dir)/opk/serialization/os_interfaces',
'<(oemcrypto_dir)/opk/serialization/tee',
'<(oemcrypto_dir)/opk/serialization/tee/include',
'<(oemcrypto_dir)/opk/ports/trusty/include/',
],
'dependencies': [
'<(oemcrypto_dir)/opk/serialization/tee/tee.gyp:opk_tee',
@@ -55,9 +51,9 @@
'sources': [
'oemcrypto_opk_dispatcher_fuzz.cc',
'<(oemcrypto_dir)/opk/serialization/test/tos_secure_buffers.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_transport_interface.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_logging.c',
'<(oemcrypto_dir)/opk/ports/trusty/serialization_adapter/shared_memory.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_shared_memory.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_transport_interface.c',
],
},
{

View File

@@ -1657,7 +1657,11 @@ void Session::close() {
void Session::GenerateNonce(int* error_counter) {
// We make one attempt. If it fails, we assume there was a nonce flood.
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), &nonce_)) {
// Using |temp_nonce| to avoid member |nonce_| being modified
// during failure.
uint32_t temp_nonce = 0;
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), &temp_nonce)) {
nonce_ = temp_nonce;
return;
}
if (error_counter) {
@@ -1667,7 +1671,8 @@ void Session::GenerateNonce(int* error_counter) {
// The following is after a 1 second pause, so it cannot be from a nonce
// flood.
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateNonce(session_id(), &nonce_));
OEMCrypto_GenerateNonce(session_id(), &temp_nonce));
nonce_ = temp_nonce;
}
}

View File

@@ -293,7 +293,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
*/
TEST_F(OEMCryptoClientTest, VersionNumber) {
const std::string log_message =
"OEMCrypto unit tests for API 18.9. Tests last updated 2025-03-11";
"OEMCrypto unit tests for API 18.10. Tests last updated 2025-06-03";
cout << " " << log_message << "\n";
cout << " "
<< "These tests are part of Android U."
@@ -302,7 +302,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
// If any of the following fail, then it is time to update the log message
// above.
EXPECT_EQ(ODK_MAJOR_VERSION, 18);
EXPECT_EQ(ODK_MINOR_VERSION, 9);
EXPECT_EQ(ODK_MINOR_VERSION, 10);
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
RecordWvProperty("test_major_version", std::to_string(ODK_MAJOR_VERSION));
RecordWvProperty("test_minor_version", std::to_string(ODK_MINOR_VERSION));
@@ -466,45 +466,58 @@ TEST_F(OEMCryptoClientTest, CheckBuildInformation_OutputLengthAPI17) {
ASSERT_GT(build_info_length, kZero)
<< "Signaling ERROR_SHORT_BUFFER should have assigned a length";
// Try again using the size they provided, ensuring that it
// is successful.
const size_t initial_estimate_length = build_info_length;
build_info.assign(build_info_length, kNullChar);
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_SUCCESS)
<< "initial_estimate_length = " << initial_estimate_length
<< ", build_info_length (output) = " << build_info_length;
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
// Ensure the real length is within the size originally specified.
// OK if final length is smaller than estimated length.
ASSERT_LE(build_info_length, initial_estimate_length);
const size_t expected_length = build_info_length;
// Force a ERROR_SHORT_BUFFER using a non-zero value.
// Note: It is assumed that vendors will provide more than a single
// character of info.
const size_t second_attempt_length =
(build_info_length >= 2) ? build_info_length / 2 : 1;
build_info.assign(second_attempt_length, kNullChar);
const size_t short_length = (expected_length >= 2) ? expected_length / 2 : 1;
build_info.assign(short_length, kNullChar);
build_info_length = build_info.size();
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER)
<< "second_attempt_length = " << second_attempt_length
<< ", build_info_length" << build_info_length;
<< "short_length = " << short_length
<< ", expected_length = " << expected_length << ", build_info_length"
<< build_info_length;
// OEM specified build info length should be larger than the
// original length if returning ERROR_SHORT_BUFFER.
ASSERT_GT(build_info_length, second_attempt_length);
ASSERT_GT(build_info_length, short_length);
// Final attempt with a buffer large enough buffer, padding to
// ensure the caller truncates.
constexpr size_t kBufferPadSize = 42;
const size_t expected_length = build_info_length;
const size_t final_attempt_length = expected_length + kBufferPadSize;
build_info.assign(final_attempt_length, kNullChar);
const size_t oversize_length = expected_length + kBufferPadSize;
build_info.assign(oversize_length, kNullChar);
build_info_length = build_info.size();
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
ASSERT_EQ(result, OEMCrypto_SUCCESS)
<< "final_attempt_length = " << final_attempt_length
<< "oversize_length = " << oversize_length
<< ", expected_length = " << expected_length
<< ", build_info_length = " << build_info_length;
<< ", build_info_length (output) = " << build_info_length;
// Ensure not empty.
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
// Ensure it was truncated down from the padded length.
ASSERT_LT(build_info_length, final_attempt_length)
ASSERT_LT(build_info_length, oversize_length)
<< "Should have truncated from oversized buffer: expected_length = "
<< expected_length;
// Ensure the real length is within the size originally specified.
// OK if final length is smaller than estimated length.
ASSERT_LE(build_info_length, expected_length);
// Ensure that length is equal to the length of the previous
// successful call.
ASSERT_EQ(build_info_length, expected_length);
}
// Verifies that OEMCrypto_BuildInformation() is behaving as expected
@@ -641,7 +654,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.
@@ -739,7 +752,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
@@ -747,7 +760,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];
@@ -757,11 +769,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));
@@ -771,25 +782,6 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
i += JsmnAncestorCount(ree_tokens, i + 1);
}
// Step 4b: Ensure all required fields of the "ree" object were found.
if (found_required_fields.size() == kReeRequiredFields.size()) return;
// Generate a list of all the missing REE fields.
std::string missing_ree_fields;
for (const auto& required_field : kReeRequiredFields) {
if (found_required_fields.find(required_field.first) !=
found_required_fields.end())
continue;
if (!missing_ree_fields.empty()) {
missing_ree_fields.append(", ");
}
missing_ree_fields.push_back('"');
missing_ree_fields.append(required_field.first);
missing_ree_fields.push_back('"');
}
FAIL() << "REE info JSON object does not contain all required keys; "
<< "missing_ree_fields = [" << missing_ree_fields
<< "], build_info = " << build_info;
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {

View File

@@ -9,7 +9,9 @@
namespace wvoec {
namespace {
bool g_generate_corpus;
}
void AppendToFile(const std::string& file_name, const char* message,
const size_t message_size) {

View File

@@ -607,11 +607,13 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, ContinueDecryptionAfterIdleAndWake) {
ASSERT_NO_FATAL_FAILURE(TestDecryptCENC());
}
namespace {
// Used to construct a specific pattern.
constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt,
size_t skip) {
return {encrypt, skip};
}
} // namespace
INSTANTIATE_TEST_SUITE_P(
CTRTests, OEMCryptoSessionTestsDecryptTests,

View File

@@ -8,18 +8,6 @@ using namespace wvoec;
namespace wvoec {
// Make this function available when in Fuzz mode because we are not inheriting
// from OEMCryptoClientTest.
const uint8_t* find(const vector<uint8_t>& message,
const vector<uint8_t>& substring) {
vector<uint8_t>::const_iterator pos = search(
message.begin(), message.end(), substring.begin(), substring.end());
if (pos == message.end()) {
return nullptr;
}
return &(*pos);
}
void SessionUtil::CreateWrappedDRMKey() {
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
// Have the device create a wrapped key.

View File

@@ -11,6 +11,7 @@ namespace wvoec {
namespace util {
#define INIT_CRC32 0xffffffff
namespace {
uint32_t wvrunningcrc32(const uint8_t* p_begin, size_t i_count,
uint32_t i_crc) {
constexpr uint32_t CRC32[256] = {
@@ -67,6 +68,7 @@ uint32_t wvrunningcrc32(const uint8_t* p_begin, size_t i_count,
return(i_crc);
}
} // namespace
uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));

View File

@@ -13,7 +13,8 @@
namespace wvoec {
namespace util {
namespace {
// Putting type in non-anonymous namespace to prevent linkage warnings.
struct HmacTestVector {
std::vector<uint8_t> key;
std::vector<uint8_t> message;
@@ -43,6 +44,7 @@ void PrintTo(const HmacTestVector& v, std::ostream* os) {
*os << "signature_sha1 = " << wvutil::b2a_hex(v.signature_sha1) << "}";
}
namespace {
std::vector<uint8_t> FromString(const std::string& s) {
return std::vector<uint8_t>(s.begin(), s.end());
}