diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aff930..b6622af 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/linux/src/log.cpp b/linux/src/log.cpp index 1e688c6..6e48727 100644 --- a/linux/src/log.cpp +++ b/linux/src/log.cpp @@ -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(sizeof(severities) / sizeof(*severities))) { + if (static_cast(level) >= sizeof(severities) / sizeof(*severities)) { fprintf(kOutputFile, "[FATAL:%s(%d):%s] Invalid log priority level: %d\n", file, line, function, level); return; diff --git a/oem_certificate_generator/oem_certificate_test_helper.py b/oem_certificate_generator/oem_certificate_test_helper.py deleted file mode 100644 index 75de4ae..0000000 --- a/oem_certificate_generator/oem_certificate_test_helper.py +++ /dev/null @@ -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) diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index 033e931..8437cbe 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -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. diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h deleted file mode 100644 index 22b1343..0000000 --- a/oemcrypto/include/level3.h +++ /dev/null @@ -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 -#include - -#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_ diff --git a/oemcrypto/include/level3_file_system.h b/oemcrypto/include/level3_file_system.h deleted file mode 100644 index 8f8fbc3..0000000 --- a/oemcrypto/include/level3_file_system.h +++ /dev/null @@ -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 -#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 diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h index 0d91b15..6d54bdc 100644 --- a/oemcrypto/odk/include/core_message_features.h +++ b/oemcrypto/odk/include/core_message_features.h @@ -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 { diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 35aa7ff..138d8cd 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -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 diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp index 30e68c4..e081961 100644 --- a/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -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; diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp index 6351a4a..292a497 100644 --- a/oemcrypto/odk/src/core_message_features.cpp +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -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; diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 2a7241f..c263d24 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -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; diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index 733d902..a4c11c3 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -1216,7 +1216,7 @@ std::vector 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 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 TestCases() { {0, 18, 7, 18, 7}, {0, 18, 8, 18, 8}, {0, 18, 9, 18, 9}, + {0, 18, 10, 18, 10}, }; return test_cases; } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c index 117877e..a5bfab6 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c @@ -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 && diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index c100648..5ae7cd8 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -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_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.c index cea8108..5450e1c 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.c @@ -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++) { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.h index bab0434..821ddce 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.h @@ -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" diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c index 9448b65..bec90cb 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.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; diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c index 676843c..36e0cc5 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c @@ -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); } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/README.md b/oemcrypto/opk/oemcrypto_ta/wtpi/README.md index 066082d..8f07d7e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/README.md +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/README.md @@ -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 diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_ref_compat_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_ref_compat_interface.h new file mode 100644 index 0000000..265e1b0 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_ref_compat_interface.h @@ -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_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_ref_compat.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_ref_compat.c new file mode 100644 index 0000000..444be5d --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_ref_compat.c @@ -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; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp index aae843a..4f51e70 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp @@ -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. diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/legacy_keywrap_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/legacy_keywrap_test.cpp index 96ae90c..6503daa 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/legacy_keywrap_test.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/legacy_keywrap_test.cpp @@ -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: diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp index 81028a1..3a8526a 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp @@ -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) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_rsa_key.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_rsa_key.cpp index c55f0b8..0cc52f4 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_rsa_key.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_rsa_key.cpp @@ -12,7 +12,10 @@ * This is a PKCS8 RSA key encoded in DER format. */ -#include "stdint.h" +#include "test_common.h" + +#include + 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, diff --git a/oemcrypto/opk/ports/linux/common/tos_transport.cpp b/oemcrypto/opk/ports/linux/common/tos_transport.cpp index e8d431e..9074bf5 100644 --- a/oemcrypto/opk/ports/linux/common/tos_transport.cpp +++ b/oemcrypto/opk/ports/linux/common/tos_transport.cpp @@ -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 diff --git a/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.cpp b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.cpp new file mode 100644 index 0000000..d28a2c4 --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.cpp @@ -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 diff --git a/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.h b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.h new file mode 100644 index 0000000..4755f52 --- /dev/null +++ b/oemcrypto/opk/ports/linux/host/oemcrypto_unittests/oemcrypto_ref_compat_test.h @@ -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 + +#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 master_key = +// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E"); +// std::vector mac_key_context = wvutil::a2b_hex( +// "2A20B95C28A52646C7192489DC9CF12257E1EB3B929D6B7D699F598BB87C4D4A"); +// std::vector enc_key_context = wvutil::a2b_hex( +// "2A20B95C28A52646C7192489DC9CF12257E1EB3B929D6B7D699F598BB87C4D4A"); +// std::vector mac_key_server = wvutil::a2b_hex( +// "6A98FB80AC7A91C7F25D5A38C8748EA85B2E390B2AEA65E5DBC06DFC8402923A"); +// std::vector mac_key_client = wvutil::a2b_hex( +// "BE5CE5801E1EA7FF235951570603CFFB4C405662EA1D641D959CC6F14431C32F"); +// std::vector enc_key = +// wvutil::a2b_hex("6A98FB80AC7A91C7F25D5A38C8748EA8"); +// std::vector enc_rsa_key_iv = +// wvutil::a2b_hex("AE32578914AC408D00AB0156F38214CD"); +// std::vector signature = wvutil::a2b_hex( +// "5173F3B523AA4DE5E5FE7D26E2913EAB0A312224D0C84B6C903E869764553555"); +std::vector 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 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 key = +// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E"); std::vector +// iv_buffer = wvutil::a2b_hex("B8D3247322351E0A4E06BB5E0BD87151"); +// std::vector signature = +// wvutil::a2b_hex("333F3815A67D92F91BF8E31479DEC4C19897059C12B6D4F10BA1CA886382DE75"); +std::vector clear_usage_entry = wvutil::a2b_hex( + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "555345454E5452591FD4AC8F1539186007EE7C66000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000"); +std::vector wrapped_usage_entry = wvutil::a2b_hex( + "333F3815A67D92F91BF8E31479DEC4C19897059C12B6D4F10BA1CA886382DE75" + "FA8917E41699C6A7BCD2D2F9F63F85E700000000000000000000000000000000" + "EE26BDE360B7C505D65A3B83384B9AACD9F64E6BB05135291AD6D337C2682C34" + "F8B5727BF1AB93E3E905D247B9E1717944547D6598723EE3B5BFBC0B0E6F9465" + "65FEC2E3869CC5878D9C0F44D72B6E2F967C9AFB4A2AA78D03B90993F7C1F80D" + "35A85BF48D625F315FE71270E6E04D586E7954FA6DB4B818962FEECEE317C0EB" + "5D29778EB125B2886AE0BDD0049BB5EB5C202C939DA0DF5B65BFEB5CB9690FE6" + "C4757A41E51F08CE9839F960B9DC71013C611A46A374A1500B5D02206A183A2A" + "0EFE55AB3FE3F5FA353F1E9E75F747A6A81291C71D6F1DEBAB55A76A05564A32" + "B28A538872CEC35F8BE21313DE0BCB309EB49B4300CA95249169033AEDA72ED2" + "54368DB0F434ACCBC958D06043800F0515CC0C618C5D54FE4804984985189450" + "FE9B105FC3605838B624CC5602FB93FC668B34DF3F6D754CC6D57DD08DB3614F" + "194A889CD9101A22D001F87D79DF8680F72FFEA213B1927FEC3A1E04C82F4A72" + "749718B3423DD3D040AD50D5AFCBCA85B8D3247322351E0A4E06BB5E0BD87151"); + +// Usage header +// std::vector key = +// wvutil::a2b_hex("E4FF574C322EF53426212CB3ED37F35E"); std::vector +// iv_buffer = wvutil::a2b_hex("CBD0C898BFC17A6D8455F1F3F746F4FE"); +// std::vector signature = +// wvutil::a2b_hex("DC6E448F7AC3A43F423310FAF0818A3C73BD067B4414707D8E0656F6CCDFF4AC"); +// std::vector master_generation_number = +// wvutil::a2b_hex("601839158FACD420") +std::vector clear_usage_header = wvutil::a2b_hex( + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000" + "555345484541445220D4AC8F1539186001000000000000001FD4AC8F15391860"); +std::vector 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_ diff --git a/oemcrypto/opk/ports/linux/rules.mk b/oemcrypto/opk/ports/linux/rules.mk index 2b1b100..f220f76 100644 --- a/oemcrypto/opk/ports/linux/rules.mk +++ b/oemcrypto/opk/ports/linux/rules.mk @@ -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. diff --git a/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp b/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp index a0a1a9e..daf6aa3 100644 --- a/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp +++ b/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp @@ -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. diff --git a/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests_main.cpp b/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests_main.cpp index 56b3817..960f09f 100644 --- a/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests_main.cpp +++ b/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests_main.cpp @@ -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. diff --git a/oemcrypto/opk/ports/optee/host/rules.mk b/oemcrypto/opk/ports/optee/host/rules.mk index f6999e4..9e8739e 100644 --- a/oemcrypto/opk/ports/optee/host/rules.mk +++ b/oemcrypto/opk/ports/optee/host/rules.mk @@ -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. diff --git a/oemcrypto/opk/ports/optee/ta/rules.mk b/oemcrypto/opk/ports/optee/ta/rules.mk index b5062c9..52956e2 100644 --- a/oemcrypto/opk/ports/optee/ta/rules.mk +++ b/oemcrypto/opk/ports/optee/ta/rules.mk @@ -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. diff --git a/oemcrypto/opk/ports/trusty/ta/reference/clang-tidy-inc.mk b/oemcrypto/opk/ports/trusty/ta/reference/clang-tidy-inc.mk index b4f22cb..bf6124a 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/clang-tidy-inc.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/clang-tidy-inc.mk @@ -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) diff --git a/oemcrypto/opk/serialization/common/bump_allocator.c b/oemcrypto/opk/serialization/common/bump_allocator.c index e2ea685..5466219 100644 --- a/oemcrypto/opk/serialization/common/bump_allocator.c +++ b/oemcrypto/opk/serialization/common/bump_allocator.c @@ -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; } diff --git a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c index 1c0efbd..ef457f5 100644 --- a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c +++ b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c @@ -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; diff --git a/oemcrypto/test/Android.mk b/oemcrypto/test/Android.mk deleted file mode 100644 index 98e9b4d..0000000 --- a/oemcrypto/test/Android.mk +++ /dev/null @@ -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) diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk deleted file mode 100644 index fde9460..0000000 --- a/oemcrypto/test/common.mk +++ /dev/null @@ -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 \ diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp index fe60be9..c93b016 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp @@ -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', ], }, { diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 4836d11..9e171dc 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -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; } } diff --git a/oemcrypto/test/oemcrypto_basic_test.cpp b/oemcrypto/test/oemcrypto_basic_test.cpp index d0b9583..9ba2f54 100644 --- a/oemcrypto/test/oemcrypto_basic_test.cpp +++ b/oemcrypto/test/oemcrypto_basic_test.cpp @@ -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(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 kReeRequiredFields = { + const std::map 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(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) { diff --git a/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp b/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp index 6b603dc..52dc0a0 100644 --- a/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp +++ b/oemcrypto/test/oemcrypto_corpus_generator_helper.cpp @@ -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) { diff --git a/oemcrypto/test/oemcrypto_decrypt_test.cpp b/oemcrypto/test/oemcrypto_decrypt_test.cpp index e95b009..228fe91 100644 --- a/oemcrypto/test/oemcrypto_decrypt_test.cpp +++ b/oemcrypto/test/oemcrypto_decrypt_test.cpp @@ -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, diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.cpp b/oemcrypto/test/oemcrypto_session_tests_helper.cpp index 175bb51..4caa7d0 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.cpp +++ b/oemcrypto/test/oemcrypto_session_tests_helper.cpp @@ -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& message, - const vector& substring) { - vector::const_iterator pos = search( - message.begin(), message.end(), substring.begin(), substring.end()); - if (pos == message.end()) { - return nullptr; - } - return &(*pos); -} - void SessionUtil::CreateWrappedDRMKey() { if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) { // Have the device create a wrapped key. diff --git a/oemcrypto/util/src/wvcrc.cpp b/oemcrypto/util/src/wvcrc.cpp index 097ca70..5e1917d 100644 --- a/oemcrypto/util/src/wvcrc.cpp +++ b/oemcrypto/util/src/wvcrc.cpp @@ -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)); diff --git a/oemcrypto/util/test/hmac_unittest.cpp b/oemcrypto/util/test/hmac_unittest.cpp index bc4f355..0cbdb61 100644 --- a/oemcrypto/util/test/hmac_unittest.cpp +++ b/oemcrypto/util/test/hmac_unittest.cpp @@ -13,7 +13,8 @@ namespace wvoec { namespace util { -namespace { + +// Putting type in non-anonymous namespace to prevent linkage warnings. struct HmacTestVector { std::vector key; std::vector 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 FromString(const std::string& s) { return std::vector(s.begin(), s.end()); }