OEMCrypto and OPK 18.10.0
GitOrigin-RevId: 987123747bd0be50fc5e4e89ec26eaa6d215bc36
This commit is contained in:
19
CHANGELOG.md
19
CHANGELOG.md
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
58
oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_ref_compat_interface.h
Normal file
58
oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_ref_compat_interface.h
Normal 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_ */
|
||||
342
oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_ref_compat.c
Normal file
342
oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_ref_compat.c
Normal 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;
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -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 \
|
||||
@@ -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',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user