Add new test files for OEMCrypto v17.2
The previous commit did not include some new files.
This commit is contained in:
4134
oemcrypto/odk/test/odk_golden_v16.cpp
Normal file
4134
oemcrypto/odk/test/odk_golden_v16.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3847
oemcrypto/odk/test/odk_golden_v17.cpp
Normal file
3847
oemcrypto/odk/test/odk_golden_v17.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_cas_interface.h
Normal file
146
oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_cas_interface.h
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/* Copyright 2023 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_CAS_INTERFACE_H_
|
||||||
|
#define OEMCRYPTO_TA_WTPI_CAS_INTERFACE_H_
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "wtpi_crypto_and_key_management_interface_layer1.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @defgroup cas CAS
|
||||||
|
*
|
||||||
|
* This interface includes functions for CAS only.
|
||||||
|
*
|
||||||
|
* If a device is not using CAS, then these functions can return
|
||||||
|
* OEMCRYPTO_NOT_IMPLEMENTED.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes CAS.
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_InitializeCas(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminates CAS.
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_TerminateCas(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a key slot descriptor for |session_id|, and places the result in
|
||||||
|
* *|key_slot_descriptor|. Key slot descriptor is used to track key slot info,
|
||||||
|
* and store additional vendor-specific properties of the key slot, if any. The
|
||||||
|
* implementation of a key slot descriptor is vendor-specific: a. a key slot
|
||||||
|
* descriptor can directly point to the allocation of a key slot, or b. a key
|
||||||
|
* slot descriptor is allocated apart from a key slot, and holds a handle to the
|
||||||
|
* key slot
|
||||||
|
*
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*
|
||||||
|
* @param[in] session_id: entitled key session id
|
||||||
|
* @param[out] key_slot_descriptor: key slot and properties holder
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if key slot descriptor cannot
|
||||||
|
* be allocated
|
||||||
|
* @retval OEMCrypto_ERROR_INVALID_CONTEXT if |key_slot_descriptor| is NULL
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_AllocateKeySlotDescriptor(OEMCrypto_SESSION session_id,
|
||||||
|
void** key_slot_descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees key slot descriptor.
|
||||||
|
*
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*
|
||||||
|
* @param[in] key_slot_descriptor: key slot and properties holder
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_FreeKeySlotDescriptor(void* key_slot_descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs entitled content key to a key slot specified in
|
||||||
|
* |key_slot_descriptor|.
|
||||||
|
*
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*
|
||||||
|
* @param[in] key_slot_descriptor: info of the destination key slot where the
|
||||||
|
* key is to be installed
|
||||||
|
* @param[in] key_handle: key to install
|
||||||
|
* @param[in] cipher_mode: the encryption mode of the media content
|
||||||
|
* @param[in] is_even: key parity flag
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL, or
|
||||||
|
* |key_handle| is invalid
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_InstallContentKey(void* key_slot_descriptor,
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle,
|
||||||
|
OEMCryptoCipherMode cipher_mode,
|
||||||
|
bool is_even);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs entitled content IV to a key slot specified in
|
||||||
|
* |key_slot_descriptor|.
|
||||||
|
*
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*
|
||||||
|
* @param[in] key_slot_descriptor: info of the destination key slot where the IV
|
||||||
|
* is to be installed
|
||||||
|
* @param[in] iv: pointer to the initialization vector to be installed
|
||||||
|
* @param[in] iv_length: size of the initialization vector
|
||||||
|
* @param[in] is_even: key parity flag
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_InstallContentIV(void* key_slot_descriptor, uint8_t* iv,
|
||||||
|
size_t iv_length, bool is_even);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key token from |key_slot_descriptor|, and places the result
|
||||||
|
* in |key_token| and sets |key_token_length| to the appropriate length. The key
|
||||||
|
* token is implementation-specific and is used by the key consumer to locate
|
||||||
|
* the key slot. It can be as simple as just an index into a shared key table,
|
||||||
|
* or it can hold more information as required by the key consumer. The key
|
||||||
|
* token is expected to leave the TEE and be used elsewhere, which is different
|
||||||
|
* from the key slot descriptor which never leaves the TEE.
|
||||||
|
*
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*
|
||||||
|
* @param[in] key_slot_descriptor: key slot info and properties holder
|
||||||
|
* @param[out] key_token: key token that identifies the key slot
|
||||||
|
* @param[in,out] key_token_length: length of the key slot, in bytes
|
||||||
|
*
|
||||||
|
* @retval OEMCrypto_SUCCESS success
|
||||||
|
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL
|
||||||
|
*/
|
||||||
|
OEMCryptoResult WTPI_GetKeyToken(void* key_slot_descriptor, uint8_t* key_token,
|
||||||
|
size_t* key_token_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key token length for OEMCrypto_GetOEMKeyToken.
|
||||||
|
*/
|
||||||
|
size_t WTPI_GetKeyTokenSize(void);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OEMCRYPTO_TA_WTPI_CAS_INTERFACE_H_ */
|
||||||
54
oemcrypto/opk/oemcrypto_ta/wtpi_reference/odk_endian.c
Normal file
54
oemcrypto/opk/oemcrypto_ta/wtpi_reference/odk_endian.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine Master
|
||||||
|
// License Agreement.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "odk_endian.h"
|
||||||
|
|
||||||
|
#define LITTLE_ENDIAN 1234
|
||||||
|
#define BIG_ENDIAN 4321
|
||||||
|
|
||||||
|
// default is little endian unless specified otherwise at build time
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
# define BYTE_ORDER LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Swap bytes in 16-bit value. */
|
||||||
|
#define __bswap_constant_16(x) \
|
||||||
|
((uint16_t)((((x) >> 8) & 0xff) | (((x)&0xff) << 8)))
|
||||||
|
|
||||||
|
/* Swap bytes in 32-bit value. */
|
||||||
|
#define __bswap_constant_32(x) \
|
||||||
|
((((x)&0xff000000u) >> 24) | (((x)&0x00ff0000u) >> 8) | \
|
||||||
|
(((x)&0x0000ff00u) << 8) | (((x)&0x000000ffu) << 24))
|
||||||
|
|
||||||
|
/* Swap bytes in 64-bit value. */
|
||||||
|
#define __bswap_constant_64(x) \
|
||||||
|
((((x)&0xff00000000000000ull) >> 56) | (((x)&0x00ff000000000000ull) >> 40) | \
|
||||||
|
(((x)&0x0000ff0000000000ull) >> 24) | (((x)&0x000000ff00000000ull) >> 8) | \
|
||||||
|
(((x)&0x00000000ff000000ull) << 8) | (((x)&0x0000000000ff0000ull) << 24) | \
|
||||||
|
(((x)&0x000000000000ff00ull) << 40) | (((x)&0x00000000000000ffull) << 56))
|
||||||
|
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
// Little endian
|
||||||
|
// swap all
|
||||||
|
|
||||||
|
uint32_t oemcrypto_htobe16(uint16_t u16) { return __bswap_constant_16(u16); }
|
||||||
|
uint32_t oemcrypto_be16toh(uint16_t u16) { return __bswap_constant_16(u16); }
|
||||||
|
uint32_t oemcrypto_htobe32(uint32_t u32) { return __bswap_constant_32(u32); }
|
||||||
|
uint32_t oemcrypto_be32toh(uint32_t u32) { return __bswap_constant_32(u32); }
|
||||||
|
uint64_t oemcrypto_htobe64(uint64_t u64) { return __bswap_constant_64(u64); }
|
||||||
|
uint64_t oemcrypto_be64toh(uint64_t u64) { return __bswap_constant_64(u64); }
|
||||||
|
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
// Big endian
|
||||||
|
// keep all
|
||||||
|
|
||||||
|
uint32_t oemcrypto_htobe16(uint16_t u16) { return u16; }
|
||||||
|
uint32_t oemcrypto_be16toh(uint16_t u16) { return u16; }
|
||||||
|
uint32_t oemcrypto_htobe32(uint32_t u32) { return u32; }
|
||||||
|
uint32_t oemcrypto_be32toh(uint32_t u32) { return u32; }
|
||||||
|
uint64_t oemcrypto_htobe64(uint64_t u64) { return u64; }
|
||||||
|
uint64_t oemcrypto_be64toh(uint64_t u64) { return u64; }
|
||||||
|
#endif
|
||||||
176
oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp
Normal file
176
oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
|
||||||
|
#include "cose_util.h"
|
||||||
|
#include "dice/cbor_reader.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
using wtpi_test::ScopedCbor;
|
||||||
|
|
||||||
|
OEMCryptoResult GetCoseSign1OffsetInBcc(uint8_t* bytes, size_t bytes_len,
|
||||||
|
size_t* offset, size_t* len) {
|
||||||
|
if (!bytes || bytes_len == 0 || !offset || !len)
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
|
||||||
|
struct CborIn in;
|
||||||
|
CborInInit(bytes, bytes_len, &in);
|
||||||
|
size_t bcc_item_count = 0;
|
||||||
|
enum CborReadResult res = CborReadArray(&in, &bcc_item_count);
|
||||||
|
if (res != CBOR_READ_RESULT_OK) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (bcc_item_count < 2) {
|
||||||
|
// There should at least be the public key and one entry.
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first item in the BCC array is the device public key
|
||||||
|
res = CborReadSkip(&in);
|
||||||
|
if (res != CBOR_READ_RESULT_OK) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t cosesign_offset = CborInOffset(&in);
|
||||||
|
// Skip the item to know the size
|
||||||
|
res = CborReadSkip(&in);
|
||||||
|
if (res != CBOR_READ_RESULT_OK) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
size_t data_size = CborInOffset(&in) - cosesign_offset;
|
||||||
|
*offset = cosesign_offset;
|
||||||
|
*len = data_size;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_cbor(cn_cbor* cn, uint32_t type) {
|
||||||
|
if (!cn) return;
|
||||||
|
|
||||||
|
cn_cbor_errback error;
|
||||||
|
cn_cbor* e;
|
||||||
|
ScopedCbor c;
|
||||||
|
switch (type) {
|
||||||
|
case CN_CBOR_BYTES:
|
||||||
|
LOGE("bytes with length %zu", cn->length);
|
||||||
|
c = ScopedCbor(cn_cbor_decode(cn->v.bytes, cn->length, &error));
|
||||||
|
e = c.get();
|
||||||
|
if (!e) {
|
||||||
|
LOGE("decoded bytes returned nil with error %d at pos %zu", error.err,
|
||||||
|
error.pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print_cbor(e, e->type);
|
||||||
|
break;
|
||||||
|
case CN_CBOR_ARRAY:
|
||||||
|
for (size_t i = 0; i < cn->length; i++) {
|
||||||
|
e = cn_cbor_index(cn, i);
|
||||||
|
LOGE("element #%zu:", i);
|
||||||
|
LOGE("type: %d", e->type);
|
||||||
|
print_cbor(e, e->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CN_CBOR_MAP:
|
||||||
|
e = cn;
|
||||||
|
for (cn_cbor* cp = e->first_child; cp && cp->next; cp = cp->next->next) {
|
||||||
|
if (cp->type == CN_CBOR_UINT) {
|
||||||
|
LOGE("cp->v.uint %lu", cp->v.uint);
|
||||||
|
} else if (cp->type == CN_CBOR_INT) {
|
||||||
|
LOGE("cp->v.sint %ld", cp->v.sint);
|
||||||
|
} else {
|
||||||
|
LOGE("tag type is %d", cp->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGE("processing other type: %d", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace wtpi_test {
|
||||||
|
// Copied and modified from open-dice test_utils.cc
|
||||||
|
ScopedCbor ExtractCwtFromCborCertificate(const uint8_t* certificate,
|
||||||
|
size_t certificate_size) {
|
||||||
|
// BCC structure is something like
|
||||||
|
/*
|
||||||
|
* ARRAY[
|
||||||
|
* MAP{ <-- DK_pub
|
||||||
|
* tag 1
|
||||||
|
* ...
|
||||||
|
* },
|
||||||
|
* ARRAY[ <-- CoseSign1
|
||||||
|
* BYTES-MAP{
|
||||||
|
* },
|
||||||
|
* MAP{
|
||||||
|
* },
|
||||||
|
* BYTES-MAP{ <-- CWT, aka "BCC payload"
|
||||||
|
* tag -4670552 <-- public key
|
||||||
|
* tag -4670553
|
||||||
|
* },
|
||||||
|
* BYTES{ <-- signature
|
||||||
|
* },
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!certificate) return nullptr;
|
||||||
|
cn_cbor_errback error;
|
||||||
|
ScopedCbor bcc(cn_cbor_decode(certificate, certificate_size, &error));
|
||||||
|
if (!bcc) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print tree of current bcc struct for debugging. May have to inspect error
|
||||||
|
// if cn_cbor_decode() fails.
|
||||||
|
// print_cbor(bcc.get(), bcc->type);
|
||||||
|
|
||||||
|
if (bcc->type != CN_CBOR_ARRAY || bcc->length < 2) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cn_cbor* inner_arr = cn_cbor_index(bcc.get(), 1);
|
||||||
|
if (!inner_arr || inner_arr->type != CN_CBOR_ARRAY || inner_arr->length < 4) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cn_cbor* payload = cn_cbor_index(inner_arr, 2);
|
||||||
|
if (!payload || payload->type != CN_CBOR_BYTES) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedCbor cwt(cn_cbor_decode(payload->v.bytes, payload->length, &error));
|
||||||
|
if (cwt && cwt->type != CN_CBOR_MAP) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return cwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from open-dice test_utils.cc
|
||||||
|
ScopedCbor ExtractPublicKeyFromCwt(const cn_cbor* cwt) {
|
||||||
|
cn_cbor_errback error;
|
||||||
|
cn_cbor* key_bytes = cn_cbor_mapget_int(cwt, -4670552);
|
||||||
|
if (!key_bytes || key_bytes->type != CN_CBOR_BYTES) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ScopedCbor key(cn_cbor_decode(key_bytes->v.bytes, key_bytes->length, &error));
|
||||||
|
if (key && key->type != CN_CBOR_MAP) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedCbor ExtractPublicKeyFromBcc(const uint8_t* bytes, size_t bytes_len) {
|
||||||
|
// Get bcc payload, which is a CBOR Web Token.
|
||||||
|
ScopedCbor cwt = ExtractCwtFromCborCertificate(bytes, bytes_len);
|
||||||
|
if (!cwt) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract public key from CWT struct
|
||||||
|
ScopedCbor public_key_cbor = ExtractPublicKeyFromCwt(cwt.get());
|
||||||
|
if (!public_key_cbor) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return public_key_cbor;
|
||||||
|
}
|
||||||
|
} // namespace wtpi_test
|
||||||
36
oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.h
Normal file
36
oemcrypto/opk/oemcrypto_ta/wtpi_test/cose_util.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
|
||||||
|
#ifndef WTPI_TEST_COSE_UTIL_H_
|
||||||
|
#define WTPI_TEST_COSE_UTIL_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "cose/cose.h"
|
||||||
|
|
||||||
|
namespace wtpi_test {
|
||||||
|
// A scoped pointer for cn_cbor.
|
||||||
|
struct CborDeleter {
|
||||||
|
void operator()(cn_cbor* c) { cn_cbor_free(c); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using ScopedCbor = std::unique_ptr<cn_cbor, CborDeleter>;
|
||||||
|
|
||||||
|
// Given BCC data in |bytes| and |bytes_len|, return a unique ptr to a cn_cbor
|
||||||
|
// struct of type CN_CBOR_BYTE that contains the public key. Must be a cn_cbor
|
||||||
|
// pointer to be compatible with COSE-C library's COSE_Sign1_validate() func
|
||||||
|
ScopedCbor ExtractPublicKeyFromBcc(const uint8_t* bytes, size_t bytes_len);
|
||||||
|
} // namespace wtpi_test
|
||||||
|
|
||||||
|
// Print basic type and tag information for a cn_cbor* tree for array, map, and
|
||||||
|
// byte CBOR types
|
||||||
|
void print_cbor(cn_cbor* cn, uint32_t type);
|
||||||
|
|
||||||
|
// Given BCC data in |bytes| and |bytes_len|, find the byte offset of the
|
||||||
|
// CoseSign1 entry and return that. Also return the length of the entry.
|
||||||
|
OEMCryptoResult GetCoseSign1OffsetInBcc(uint8_t* bytes, size_t bytes_len,
|
||||||
|
size_t* offset, size_t* len);
|
||||||
|
#endif
|
||||||
51
oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_cas.c
Normal file
51
oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_cas.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* 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 "wtpi_cas_interface.h"
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InitializeCas(void) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_TerminateCas(void) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_AllocateKeySlotDescriptor(OEMCrypto_SESSION session_id,
|
||||||
|
void** key_slot_descriptor) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_FreeKeySlotDescriptor(void* key_slot_descriptor) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentKey(void* key_slot_descriptor,
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle,
|
||||||
|
OEMCryptoCipherMode cipher_mode,
|
||||||
|
bool is_even) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentIV(void* key_slot_descriptor, uint8_t* iv,
|
||||||
|
size_t iv_length, bool is_even) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetKeyToken(void* key_slot_descriptor, uint8_t* key_token,
|
||||||
|
size_t* key_token_length) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_GetKeyTokenSize(void) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "oemcrypto_check_macros.h"
|
||||||
|
#include "wtpi_persistent_storage.h"
|
||||||
|
|
||||||
|
/* This implementation does not meet persistent storage reqiurements. It will
|
||||||
|
* pass most unit tests, but will fail under more realistic scenarios such as
|
||||||
|
* reboot. This will not work on an actual device. This file should be replaced
|
||||||
|
* with an implementation that stores data securely and persistently across
|
||||||
|
* reboots.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FAKE_PERSISTENT_DATA_MAX_SIZE 5 * 1024
|
||||||
|
static uint8_t fake_persistent_data[FAKE_PERSISTENT_DATA_MAX_SIZE];
|
||||||
|
static size_t pdata_used = 0;
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_PrepareStoredPersistentData(void) {
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(data);
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(data_length);
|
||||||
|
|
||||||
|
if (pdata_used == 0) {
|
||||||
|
return OPK_ERROR_NO_PERSISTENT_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*data_length < pdata_used) {
|
||||||
|
*data_length = pdata_used;
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data, fake_persistent_data, pdata_used);
|
||||||
|
*data_length = pdata_used;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_StorePersistentData(const uint8_t* data,
|
||||||
|
size_t data_length) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(data);
|
||||||
|
|
||||||
|
if (data_length > FAKE_PERSISTENT_DATA_MAX_SIZE) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
memset(fake_persistent_data, 0, FAKE_PERSISTENT_DATA_MAX_SIZE);
|
||||||
|
memcpy(fake_persistent_data, data, data_length);
|
||||||
|
pdata_used = data_length;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
59
oemcrypto/opk/ports/linux/Makefile
Normal file
59
oemcrypto/opk/ports/linux/Makefile
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# $CDM_DIR must be defined as the path to the top level of the OPK release
|
||||||
|
ifndef CDM_DIR
|
||||||
|
$(error CDM_DIR is undefined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.EXPORT_ALL_VARIABLES:
|
||||||
|
|
||||||
|
WTPI_BUILD_INFO := Linux_TEE_Simulator
|
||||||
|
ARCH := 64
|
||||||
|
IS_ARM := 0
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: host ta
|
||||||
|
|
||||||
|
.PHONY: ta
|
||||||
|
ta: oemcrypto_ta wtpi_ta
|
||||||
|
|
||||||
|
.PHONY: host
|
||||||
|
host: oemcrypto_helloworld oemcrypto_unittests wtpi_unittests
|
||||||
|
|
||||||
|
.PHONY: oemcrypto_ta
|
||||||
|
oemcrypto_ta:
|
||||||
|
+$(MAKE) -C ta/oemcrypto_ta
|
||||||
|
|
||||||
|
.PHONY: wtpi_ta
|
||||||
|
wtpi_ta:
|
||||||
|
+$(MAKE) -C ta/wtpi_test_ta
|
||||||
|
|
||||||
|
.PHONY: liboemcrypto
|
||||||
|
liboemcrypto:
|
||||||
|
+$(MAKE) -C host/liboemcrypto
|
||||||
|
|
||||||
|
.PHONY: oemcrypto_helloworld
|
||||||
|
oemcrypto_helloworld: liboemcrypto
|
||||||
|
+$(MAKE) -C host/oemcrypto_helloworld
|
||||||
|
|
||||||
|
.PHONY: oemcrypto_unittests
|
||||||
|
oemcrypto_unittests: liboemcrypto
|
||||||
|
+$(MAKE) -C host/oemcrypto_unittests
|
||||||
|
|
||||||
|
.PHONY: wtpi_unittests
|
||||||
|
wtpi_unittests:
|
||||||
|
+$(MAKE) -C host/wtpi_unittests
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
+$(MAKE) -C ta/oemcrypto_ta clean
|
||||||
|
+$(MAKE) -C ta/wtpi_test_ta clean
|
||||||
|
+$(MAKE) -C host/liboemcrypto clean
|
||||||
|
+$(MAKE) -C host/oemcrypto_helloworld clean
|
||||||
|
+$(MAKE) -C host/oemcrypto_unittests clean
|
||||||
|
+$(MAKE) -C host/wtpi_unittests clean
|
||||||
|
|
||||||
105
oemcrypto/opk/ports/linux/README.md
Normal file
105
oemcrypto/opk/ports/linux/README.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Linux example port
|
||||||
|
|
||||||
|
This folder contains an end-to-end OPK example implementation using a simulated
|
||||||
|
REE/TEE boundary. Everything runs on the REE in Linux.
|
||||||
|
|
||||||
|
** This implementation is for testing only! There is no reason for the provided
|
||||||
|
TA code to ever run in a non-secure environment in production. **
|
||||||
|
|
||||||
|
The following examples can be run
|
||||||
|
- `oemcrypto_unittests`: runs OEMCrypto API unit tests against the OEMCrypto TA
|
||||||
|
- `wtpi_unittests`: runs WTPI unit tests against the WTPI Test TA
|
||||||
|
- `oemcrypto_helloworld`: calls OEMCrypto_Initialize() to prove that the
|
||||||
|
serialization and execution works correctly between the REE and TEE.
|
||||||
|
|
||||||
|
Before running each example, make sure the matching TEE simulator has been
|
||||||
|
started. The `oemcrypto_unittests` and `oemcrypto_helloworld` executables work
|
||||||
|
with tee_simulator_oemcrypto, and `wtpi_unittests` work with tee_simulator_wtpi.
|
||||||
|
Running in the background is sufficient, eg `./tee_simulator_oemcrypto &`.
|
||||||
|
|
||||||
|
Instead of running in the TEE as a trusted app, the TA code is compiled as
|
||||||
|
a REE-side binary. The transport and shared memory interfaces of both host and
|
||||||
|
trusted apps are implemented using the POSIX shared memory and semaphore
|
||||||
|
libraries. The request and response messages are located in a shared memory
|
||||||
|
block and the request and response semaphores are used to synchronize the REE
|
||||||
|
and TEE communication by signaling when messages are available.
|
||||||
|
|
||||||
|
# Build and run
|
||||||
|
|
||||||
|
```
|
||||||
|
$ make -C oemcrypto/opk/ports/linux all
|
||||||
|
|
||||||
|
# Run simulated TEE with OEMCrypto TA
|
||||||
|
# If scripting around this, wait 1 second to allow TA time to start
|
||||||
|
$ ./oemcrypto_ta &
|
||||||
|
|
||||||
|
# Capture pid
|
||||||
|
$ export TEE_SIM_PID=$!
|
||||||
|
|
||||||
|
# Run host app
|
||||||
|
$ ./oemcrypto_helloworld
|
||||||
|
|
||||||
|
# Stop TEE simulator
|
||||||
|
$ kill $TEE_SIM_PID
|
||||||
|
```
|
||||||
|
|
||||||
|
# Code organization
|
||||||
|
|
||||||
|
```
|
||||||
|
├── common
|
||||||
|
│ └── TOS implementation, POSIX resources
|
||||||
|
├── host
|
||||||
|
│ ├── liboemcrypto
|
||||||
|
│ │ └── builds liboemcrypto.so
|
||||||
|
│ ├── oemcrypto_helloworld
|
||||||
|
│ │ └── builds oemcrypto_helloworld executable
|
||||||
|
│ ├── oemcrypto_unittests
|
||||||
|
│ │ └── builds oemcrypto_unittests executable
|
||||||
|
│ └── wtpi_unittests
|
||||||
|
│ └── builds wtpi_unittests executable
|
||||||
|
├── rules.mk # Common build rules for all executables
|
||||||
|
└── ta
|
||||||
|
├── common
|
||||||
|
│ ├── clock.cpp
|
||||||
|
│ ├── tee_simulator.cpp # Entry point for TAs
|
||||||
|
│ └── wtpi_impl
|
||||||
|
│ └── WTPI implementations specific to Linux test port
|
||||||
|
├── oemcrypto_ta
|
||||||
|
│ └── builds simulated OEMCrypto TA
|
||||||
|
├── gyp
|
||||||
|
│ └── internal GYP files
|
||||||
|
└── wtpi_test_ta
|
||||||
|
└── builds simulated WTPI Test TA
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# OPK_SendMessage
|
||||||
|
|
||||||
|
```
|
||||||
|
+-----+ +-------------------+ +---------------+ +-------------------+ +-----+
|
||||||
|
| REE | | ResponseSemaphore | | SharedMemory | | RequestSemaphore | | TEE |
|
||||||
|
+-----+ +-------------------+ +---------------+ +-------------------+ +-----+
|
||||||
|
| | | | |
|
||||||
|
| | | | wait |
|
||||||
|
| | | |<-------------|
|
||||||
|
| | | | |
|
||||||
|
| write request | | | |
|
||||||
|
|----------------------------------->| | |
|
||||||
|
| | | | |
|
||||||
|
| post | | | |
|
||||||
|
|------------------------------------------------------->| |
|
||||||
|
| | | | |
|
||||||
|
| wait | | | |
|
||||||
|
|--------------->| | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | read request |
|
||||||
|
| | |<---------------------------------|
|
||||||
|
| | | | |
|
||||||
|
| | | | post |
|
||||||
|
| |<-----------------------------------------------------|
|
||||||
|
| | | | |
|
||||||
|
| read response | | | |
|
||||||
|
|----------------------------------->| | |
|
||||||
|
| | | | |
|
||||||
|
```
|
||||||
53
oemcrypto/opk/ports/linux/cas/Makefile
Normal file
53
oemcrypto/opk/ports/linux/cas/Makefile
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# $CDM_DIR must be defined as the path to the top level of the OPK release
|
||||||
|
ifndef CDM_DIR
|
||||||
|
$(error CDM_DIR is undefined)
|
||||||
|
endif
|
||||||
|
|
||||||
|
.EXPORT_ALL_VARIABLES:
|
||||||
|
|
||||||
|
ARCH := 64
|
||||||
|
IS_ARM := 0
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: ree tee
|
||||||
|
|
||||||
|
.PHONY: ree
|
||||||
|
ree: hello_world cas_unittests
|
||||||
|
|
||||||
|
.PHONY: tee
|
||||||
|
tee: tee_simulator_cas
|
||||||
|
|
||||||
|
.PHONY: liboemcrypto
|
||||||
|
liboemcrypto:
|
||||||
|
+$(MAKE) -C ree/liboemcrypto
|
||||||
|
|
||||||
|
.PHONY: libtuner
|
||||||
|
libtuner:
|
||||||
|
+$(MAKE) -C ree/libtuner
|
||||||
|
|
||||||
|
.PHONY: hello_world
|
||||||
|
hello_world: liboemcrypto libtuner
|
||||||
|
+$(MAKE) -C ree/hello_world
|
||||||
|
|
||||||
|
.PHONY: cas_unittests
|
||||||
|
cas_unittests: liboemcrypto libtuner
|
||||||
|
+$(MAKE) -C ree/cas_unittests
|
||||||
|
|
||||||
|
.PHONY: tee_simulator_cas
|
||||||
|
tee_simulator_cas:
|
||||||
|
+$(MAKE) -C tee/tee_simulator_cas
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
+$(MAKE) -C tee/tee_simulator_cas clean
|
||||||
|
+$(MAKE) -C ree/liboemcrypto clean
|
||||||
|
+$(MAKE) -C ree/libtuner clean
|
||||||
|
+$(MAKE) -C ree/hello_world clean
|
||||||
|
+$(MAKE) -C ree/cas_unittests clean
|
||||||
|
|
||||||
227
oemcrypto/opk/ports/linux/cas/README.md
Normal file
227
oemcrypto/opk/ports/linux/cas/README.md
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
# OEMCrypto CAS demo on Linux
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
to build: `CDM_DIR=<path_to_cdm_dir> ./scripts/build.sh`
|
||||||
|
to run: `CDM_DIR=<path_to_cdm_dir> ./scripts/run.sh`
|
||||||
|
|
||||||
|
Can set CDM_DIR as a global variable, or inject every time you run.
|
||||||
|
|
||||||
|
To build manually, call `CDM_DIR=<path_to_cdm_dir> make liboemcrypto -j32`
|
||||||
|
from this directory. Feel free to replace `liboemcrypto` with whichever make
|
||||||
|
recipe you want.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This is a Linux-based demo of the OEMCrypto CAS functionality in the OPK. The
|
||||||
|
demo itself is very narrow in scope, and is not suitable for production without
|
||||||
|
significant modification.
|
||||||
|
|
||||||
|
In particular, the "TA" portion runs as a separate process in the REE for ease
|
||||||
|
of debugging and inspection. At the very least, this code must be ported to a
|
||||||
|
TEE in order to run in a secure manner.
|
||||||
|
|
||||||
|
This project demonstrates the connection from REE (liboemcrypto.so and
|
||||||
|
libtuner.so) to the TA (tee_simulator_cas) to call OEMCrypto functions
|
||||||
|
and the Tuner descrambler together.
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
This CAS demo is a modified version of the Linux OEMCrypto port
|
||||||
|
(oemcrypto/opk/ports/linux). It generally follows the same design as that port,
|
||||||
|
such as choosing to run the TA code in a separate Linux process rather than a
|
||||||
|
TEE.
|
||||||
|
|
||||||
|
The CAS demo builds three types of output:
|
||||||
|
|
||||||
|
1. _App level_ (hello_world, cas_unittests). These call OEMCrypto and Tuner
|
||||||
|
functions directly. A real system would use plugins, CDM, etc.
|
||||||
|
2. _Libraries_ (liboemcrypto.so and libtuner.so). These serialize the OEMCrypto
|
||||||
|
and Tuner function calls into message bytes to send to the TA.
|
||||||
|
3. _TA_ (tee_simulator_cas). This is a single application that combines all code
|
||||||
|
for message deserialization, OEMCrypto function execution, Tuner descrambling,
|
||||||
|
and data sharing for CAS ECM keys. Because it is a single binary, the shared
|
||||||
|
data can exist as global variables or statically linked functions. A real
|
||||||
|
system would likely separate the OEMCrypto, descrambling, and shared data into
|
||||||
|
individual trusted apps.
|
||||||
|
|
||||||
|
The app and libraries are expected to run in a REE no matter what. The "TA"
|
||||||
|
portion should realistically run in a TEE, but for the purposes of this demo
|
||||||
|
all TA code runs in a separate Linux process. This avoids the need to support
|
||||||
|
TEE-specific communication protocols -- instead, the two Linux apps use POSIX
|
||||||
|
shared mem and semaphores to pass messages back and forth.
|
||||||
|
|
||||||
|
### Apps
|
||||||
|
|
||||||
|
hello_world calls basic OEMCrypto and Tuner functions to prove that the
|
||||||
|
serialization and deserialization paths work and can communicate with the
|
||||||
|
tee_simulator_cas process.
|
||||||
|
|
||||||
|
cas_unittests is intended to run the expected OEMCrypto setup functions before
|
||||||
|
calling Tuner_Decrypt() on real content. However, this is incomplete until we
|
||||||
|
can cleanly extract sample content and matching entitlement keys for a local
|
||||||
|
test (no network access).
|
||||||
|
|
||||||
|
### Libraries
|
||||||
|
|
||||||
|
liboemcrypto.so is almost the exact same as an OEMCrypto implementation for a
|
||||||
|
DRM-only (not CAS) target. Like a typical DRM use case, this serializes all
|
||||||
|
OEMCrypto functions for sending to the TEE. The one minor difference is the
|
||||||
|
addition of a CAS-specific field in some data structures.
|
||||||
|
|
||||||
|
libtuner.so is new, specific to this demo. It uses the same serialization
|
||||||
|
scheme as liboemcrypto.so, but for a single Decrypt() function. In a real
|
||||||
|
system this might not be necessary at all, as a platform-specific descrambler
|
||||||
|
can take its place. The `tuner_ree_serialization` files provide the REE-side
|
||||||
|
serialization code used in this library, while the *_tee_* equivalent is used
|
||||||
|
in the TA.
|
||||||
|
|
||||||
|
### TA
|
||||||
|
|
||||||
|
The TA code runs in a single application called `tee_simulator_cas`. This is
|
||||||
|
similar to the name of the Linux OPK port, which is "tee simulator". This
|
||||||
|
application runs in Linux userspace as a while loop, watching when POSIX
|
||||||
|
shared memory contains messages from liboemcrypto.so and libtuner.so. Then those
|
||||||
|
messages are deserialized and executed as either OEMCrypto or Tuner functions.
|
||||||
|
|
||||||
|
Apart from the while loop and POSIX resource management, the rest of the code
|
||||||
|
is in C and should be portable to any platform-specific use case with the OPK.
|
||||||
|
|
||||||
|
The while loop and POSIX messaging scheme is not intended to be used on a real
|
||||||
|
device. It is a shortcut to run easily on Linux.
|
||||||
|
|
||||||
|
One limitation of having all TA code run in a single application is that
|
||||||
|
incoming messages are received in a single thread. So liboemcrypto.so and
|
||||||
|
libtuner.so functions can be called from the app in multiple threads, but they
|
||||||
|
will be received and executed sequentially, potentially blocking the calling
|
||||||
|
threads until previous function execution is complete. This is a limitation of
|
||||||
|
the OPK C functions used in message deserialization and temporary memory
|
||||||
|
allocation -- both OEMCrypto and Tuner deserialization paths have to use the
|
||||||
|
same statically allocated resouces in this case, which we cannot easily thread
|
||||||
|
proof.
|
||||||
|
|
||||||
|
## How to modify this demo for a real world use case
|
||||||
|
|
||||||
|
This demo cuts corners in a few ways and is not usable as-is for production. A
|
||||||
|
few modifications are necessary:
|
||||||
|
|
||||||
|
1. Separation of OEMCrypto, Descrambler, and data share in TEE. Add platform-
|
||||||
|
specific TA entry points for each.
|
||||||
|
2. Completely rewrite data_share_impl.c to reflect platform-specific key
|
||||||
|
descriptors, key tokens, key table, and concurrency. Possible changes to
|
||||||
|
wtpi_cas.c to match.
|
||||||
|
3. Replace libtuner.so and Tuner_Decrypt() with actual tuner integration if
|
||||||
|
applicable.
|
||||||
|
|
||||||
|
More details in sections below
|
||||||
|
|
||||||
|
### Move OEMCrypto, Tuner, data share to TEE
|
||||||
|
|
||||||
|
A real system would likely have completely separate OEMCrypto, Tuner, and data
|
||||||
|
share portions (3 parts) running in a TEE. In order to access the shared data,
|
||||||
|
TEE-specific mechanisms would need to be used. Using the code in this demo as a
|
||||||
|
reference, those three parts would be divided roughly as follows:
|
||||||
|
|
||||||
|
1. OEMCrypto: all `opk_base_ta_sources`, `wtpi_impl_sources`,
|
||||||
|
`boringssl_sources`, and `dice_sources` for a typical OEMCrypto build. Also
|
||||||
|
`wtpi_cas.c` to access shared_data.
|
||||||
|
2. Tuner: `tuner_impl.c`, `tuner_tee_serialization.c`
|
||||||
|
3. Data share: `data_share_impl.c`
|
||||||
|
|
||||||
|
The source code in each portion above will need to be modified to access the
|
||||||
|
shared data in a TEE-specific way.
|
||||||
|
|
||||||
|
For example, running in OP-TEE would require the shared data to be a separate
|
||||||
|
TA. OEMCrypto would call the wtpi_cas functions to access the data, and those
|
||||||
|
implementations would use TEE_OpenTASession()/TEE_InvokeTACommand()/
|
||||||
|
TA_CloseTASession() GlobalPlatform methods to access that TA. The Tuner would
|
||||||
|
use the same functions to acess the shared data from its side.
|
||||||
|
|
||||||
|
Similarly, the `tee_simulator_cas/tee_simulator.cpp` file would need to be
|
||||||
|
completely replaced with TEE-specific entry points for the OEMCrypto and Tuner
|
||||||
|
portions.
|
||||||
|
|
||||||
|
A Tuner TA using these files might not be necessary, as it might already exist
|
||||||
|
on some platforms.
|
||||||
|
|
||||||
|
### More secure and portable Key Tokens
|
||||||
|
|
||||||
|
The data returned by OEMCrypto_GetOEMKeyToken() is visible to the REE. As such,
|
||||||
|
it should not convey any information about the underlying key data, and should
|
||||||
|
be generally tamperproof. The demo implementation here only uses the key table
|
||||||
|
index and does not check for tampering.
|
||||||
|
|
||||||
|
In particular, the functions in `data_share.h` will need updated implementations
|
||||||
|
to match any new key token and key descriptor design.
|
||||||
|
|
||||||
|
This demo leverages the OEMCrypto code to take advantage of the common key
|
||||||
|
handle creation and management. Since the TA code executes in the same binary,
|
||||||
|
an OEMCrypto key handle can be directly used in the Tuner decrypt function. If
|
||||||
|
everything is separated, the key handle may not be directly shareable the way
|
||||||
|
it is in this demo.
|
||||||
|
|
||||||
|
### Possible changes to data share mutex
|
||||||
|
|
||||||
|
The demo uses a data share with a global mutex to guard against simultaneous
|
||||||
|
reads and writes. Some TEEs may not be able to use the same POSIX mutex
|
||||||
|
structures, and may need to rely on other mechanisms. Some TEE's already allow
|
||||||
|
only one TA accessor at a time, effectively accomplishing the same end goal as a
|
||||||
|
mutex.
|
||||||
|
|
||||||
|
### REE/TEE communication
|
||||||
|
|
||||||
|
The current serialization interface uses POSIX shared memory to communicate
|
||||||
|
between the REE and TEE. This will need to be changed to a TEE-specific
|
||||||
|
mechanism. In particular, the TOS functions (the files under
|
||||||
|
`oemcrypto/opk/ports/linux/common/`) will need to be modified. See the OP-TEE
|
||||||
|
port or Trusty port `tos_` files for example implementations of
|
||||||
|
this REE/TEE communication layer in a real world example.
|
||||||
|
|
||||||
|
### Integration with more realistic REE code
|
||||||
|
|
||||||
|
This demo uses Google Test on the REE to call the OEMCrypto and Tuner functions.
|
||||||
|
This is not realistic. The MediaCAS plugin would be a better exerciser of the
|
||||||
|
code, either in VTS tests or other high-level integration suite.
|
||||||
|
|
||||||
|
### Improved data share management
|
||||||
|
|
||||||
|
This demo uses a rudimentary data share implementation that only writes more
|
||||||
|
information without freeing up unused slots. None of the shared key data from
|
||||||
|
OEMCrypto will be free'd, so eventually the key table will run out of space,
|
||||||
|
even when sessions are closed. An improved implementation would use
|
||||||
|
WTPI_FreeKeySlotDescriptor() to clean up a slot on session close.
|
||||||
|
|
||||||
|
## Folder structure
|
||||||
|
|
||||||
|
oemcrypto/opk/ports/linux/cas
|
||||||
|
├── Makefile
|
||||||
|
├── README.md
|
||||||
|
├── ree
|
||||||
|
│ ├── cas_unittests
|
||||||
|
│ │ ├── cas_tests.cpp
|
||||||
|
│ │ └── Makefile
|
||||||
|
│ ├── hello_world
|
||||||
|
│ │ ├── main.c
|
||||||
|
│ │ └── Makefile
|
||||||
|
│ ├── liboemcrypto
|
||||||
|
│ │ └── Makefile
|
||||||
|
│ ├── libtuner
|
||||||
|
│ │ └── Makefile
|
||||||
|
│ ├── tuner_ree_serialization.c
|
||||||
|
│ └── tuner_ree_serialization.h
|
||||||
|
├── scripts
|
||||||
|
│ ├── build.sh
|
||||||
|
│ └── run.sh
|
||||||
|
├── tee
|
||||||
|
│ ├── tee_simulator_cas
|
||||||
|
│ │ ├── data_share.h
|
||||||
|
│ │ ├── data_share_impl.c
|
||||||
|
│ │ ├── Makefile
|
||||||
|
│ │ ├── tee_simulator.cpp
|
||||||
|
│ │ ├── tuner_impl.c
|
||||||
|
│ │ └── wtpi_cas.c
|
||||||
|
│ ├── tuner_tee_serialization.c
|
||||||
|
│ └── tuner_tee_serialization.h
|
||||||
|
└── tuner_hal.h
|
||||||
|
|
||||||
|
9 directories, 21 files
|
||||||
41
oemcrypto/opk/ports/linux/cas/ree/cas_unittests/Makefile
Normal file
41
oemcrypto/opk/ports/linux/cas/ree/cas_unittests/Makefile
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/cas/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/cas/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(oemcrypto_unittests_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(oemcrypto_unittests_includes) \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/ree \
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -ldl \
|
||||||
|
-L$(builddir)/../liboemcrypto/ -loemcrypto \
|
||||||
|
-L$(builddir)/../libtuner/ -ltuner \
|
||||||
|
-static-libstdc++ \
|
||||||
|
|
||||||
|
cppflags += \
|
||||||
|
-DOPENSSL_NO_ASM \
|
||||||
|
-Wnon-virtual-dtor \
|
||||||
|
-DCAS_TEST \
|
||||||
|
|
||||||
|
include ../../../rules.mk
|
||||||
|
|
||||||
|
|
||||||
35
oemcrypto/opk/ports/linux/cas/ree/hello_world/Makefile
Normal file
35
oemcrypto/opk/ports/linux/cas/ree/hello_world/Makefile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/cas/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/cas/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/ree/hello_world/main.c \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/include \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/ree \
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -ldl \
|
||||||
|
-L$(builddir)/../liboemcrypto/ -loemcrypto \
|
||||||
|
-L$(builddir)/../libtuner/ -ltuner \
|
||||||
|
|
||||||
|
include ../../../rules.mk
|
||||||
|
|
||||||
|
|
||||||
31
oemcrypto/opk/ports/linux/cas/ree/hello_world/main.c
Normal file
31
oemcrypto/opk/ports/linux/cas/ree/hello_world/main.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "tuner_hal.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Hello world\n");
|
||||||
|
|
||||||
|
OEMCryptoResult res;
|
||||||
|
res = OEMCrypto_Initialize();
|
||||||
|
printf("OEMCrypto_Initialize() returned %d\n", res);
|
||||||
|
|
||||||
|
// TODO: get expected call hierarchy for example usage
|
||||||
|
// OEMCrypto_CreateEntitledKeySession()
|
||||||
|
// OEMCrypto_LoadKeys()
|
||||||
|
// OEMCrypto_LoadCasECMKeys()
|
||||||
|
// OEMCrypto_GetOEMKeyToken()
|
||||||
|
|
||||||
|
// TODO: populate with test data
|
||||||
|
TunerHalResult res2 = TunerHal_Decrypt(NULL, 0, 0, NULL, 0, NULL);
|
||||||
|
printf("TunerHal_Decrypt() returned %d\n", res2);
|
||||||
|
|
||||||
|
OEMCrypto_Terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
39
oemcrypto/opk/ports/linux/cas/ree/liboemcrypto/Makefile
Normal file
39
oemcrypto/opk/ports/linux/cas/ree/liboemcrypto/Makefile
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/cas/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/cas/$(project)/
|
||||||
|
output = $(project).so
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp \
|
||||||
|
$(liboemcrypto_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/include \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto \
|
||||||
|
$(liboemcrypto_includes) \
|
||||||
|
|
||||||
|
cflags += \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"tee_simulator_cas\" \
|
||||||
|
|
||||||
|
ldflags = -lpthread -shared -lrt
|
||||||
|
|
||||||
|
include ../../../rules.mk
|
||||||
|
|
||||||
43
oemcrypto/opk/ports/linux/cas/ree/libtuner/Makefile
Normal file
43
oemcrypto/opk/ports/linux/cas/ree/libtuner/Makefile
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/cas/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/cas/$(project)/
|
||||||
|
output = $(project).so
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/ree/tuner_ree_serialization.c \
|
||||||
|
$(liboemcrypto_sources) \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/ \
|
||||||
|
$(liboemcrypto_includes) \
|
||||||
|
$(oemcrypto_dir)/opk/oemcrypto_ta \
|
||||||
|
$(oemcrypto_dir)/include \
|
||||||
|
|
||||||
|
# Here the liboemcrypto.so and libtuner.so transport layers share the same
|
||||||
|
# destination, which is a POSIX shm with the tag "tee_simulator_cas"
|
||||||
|
cflags += \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"tee_simulator_cas\" \
|
||||||
|
|
||||||
|
ldflags = -lpthread -shared -lrt
|
||||||
|
|
||||||
|
include ../../../rules.mk
|
||||||
|
|
||||||
135
oemcrypto/opk/ports/linux/cas/ree/tuner_ree_serialization.c
Normal file
135
oemcrypto/opk/ports/linux/cas/ree/tuner_ree_serialization.c
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <inttypes.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "GEN_common_serializer.h"
|
||||||
|
#include "GEN_ree_serializer.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "api_support.h"
|
||||||
|
#include "bump_allocator.h"
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "message_debug.h"
|
||||||
|
#include "ree_special_cases.h"
|
||||||
|
#include "ree_version.h"
|
||||||
|
#include "shared_buffer_allocator.h"
|
||||||
|
#include "tos_shared_memory_interface.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
#include "tuner_ree_serialization.h"
|
||||||
|
|
||||||
|
#define TUNER_HAL_DECRYPT_API_VALUE 12345
|
||||||
|
|
||||||
|
TunerHalResult TunerHal_Decrypt(
|
||||||
|
const uint8_t* key_token,
|
||||||
|
size_t key_token_length,
|
||||||
|
KeyParityType key_parity,
|
||||||
|
const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||||
|
size_t samples_length, // the number of samples.
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||||
|
pthread_mutex_lock(&api_lock);
|
||||||
|
TunerHalResult result = TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
ODK_Message request = ODK_Message_Create(NULL, 0);
|
||||||
|
ODK_Message response = ODK_Message_Create(NULL, 0);
|
||||||
|
API_Initialize();
|
||||||
|
request =
|
||||||
|
// OPK_Pack_TunerHal_Decrypt_Request(session, samples, samples_length, pattern);
|
||||||
|
OPK_Pack_TunerHal_Decrypt_Request(key_token, key_token_length, key_parity, samples, samples_length, pattern);
|
||||||
|
if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) {
|
||||||
|
if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) {
|
||||||
|
api_result = TUNER_HAL_ERROR_BUFFER_TOO_LARGE;
|
||||||
|
} else {
|
||||||
|
api_result = TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
goto cleanup_and_return;
|
||||||
|
}
|
||||||
|
response = API_Transact(&request);
|
||||||
|
OPK_Unpack_TunerHal_Decrypt_Response(&response, &result);
|
||||||
|
|
||||||
|
if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) {
|
||||||
|
api_result = TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
cleanup_and_return:
|
||||||
|
TOS_Transport_ReleaseMessage(&request);
|
||||||
|
TOS_Transport_ReleaseMessage(&response);
|
||||||
|
|
||||||
|
result = API_CheckResult(result);
|
||||||
|
pthread_mutex_unlock(&api_lock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ODK_Message OPK_Pack_TunerHal_Decrypt_Request(
|
||||||
|
const uint8_t* key_token,
|
||||||
|
size_t key_token_length,
|
||||||
|
KeyParityType key_parity,
|
||||||
|
const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||||
|
size_t samples_length, // the number of samples.
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||||
|
uint32_t api_value =
|
||||||
|
TUNER_HAL_DECRYPT_API_VALUE; // TODO: how will this interact on the TEE
|
||||||
|
// side?
|
||||||
|
ODK_Message msg = TOS_Transport_GetRequest();
|
||||||
|
OPK_Pack_uint32_t(&msg, &api_value);
|
||||||
|
uint64_t timestamp = time(0);
|
||||||
|
OPK_Pack_uint64_t(&msg, ×tamp);
|
||||||
|
|
||||||
|
OPK_Pack_size_t(&msg, &key_token_length);
|
||||||
|
OPK_PackMemory(&msg, (const uint8_t*)key_token,
|
||||||
|
OPK_ToLengthType(key_token_length));
|
||||||
|
|
||||||
|
OPK_Pack_uint32_t(&msg, &key_parity);
|
||||||
|
|
||||||
|
OPK_Pack_size_t(&msg, &samples_length);
|
||||||
|
/* pack object array with packer function OPK_Pack_OEMCrypto_SampleDescription
|
||||||
|
*/
|
||||||
|
ODK_Message* const odk_message = &msg;
|
||||||
|
const void* const objs = (const void*)samples;
|
||||||
|
const LengthType count = OPK_ToLengthType(samples_length);
|
||||||
|
const size_t size = sizeof(OEMCrypto_SampleDescription);
|
||||||
|
const bool is_null = objs == NULL || OPK_LengthIsNull(count);
|
||||||
|
if (!OPK_PackBoolValue(odk_message, is_null)) {
|
||||||
|
for (size_t i = 0; i < OPK_ToSizeT(count); i++) {
|
||||||
|
OPK_Pack_OEMCrypto_SampleDescription(
|
||||||
|
odk_message, (const OEMCrypto_SampleDescription*)(objs + i * size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc(&msg, pattern);
|
||||||
|
OPK_PackEOM(&msg);
|
||||||
|
OPK_SharedBuffer_FinalizePacking();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPK_Unpack_TunerHal_Decrypt_Response(ODK_Message* msg,
|
||||||
|
TunerHalResult* result) {
|
||||||
|
uint32_t api_value = UINT32_MAX;
|
||||||
|
OPK_Unpack_uint32_t(msg, &api_value);
|
||||||
|
if (api_value != TUNER_HAL_DECRYPT_API_VALUE)
|
||||||
|
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
|
||||||
|
OPK_Unpack_uint32_t(msg, result);
|
||||||
|
if (!Is_Valid_TunerHalResult(*result)) {
|
||||||
|
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE);
|
||||||
|
}
|
||||||
|
OPK_UnpackEOM(msg);
|
||||||
|
|
||||||
|
if (SuccessResult(*result)) {
|
||||||
|
OPK_SharedBuffer_FinalizeUnpacking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Is_Valid_TunerHalResult(uint32_t value) {
|
||||||
|
switch (value) {
|
||||||
|
case 0: /* TUNER_HAL_SUCCESS */
|
||||||
|
case 1: /* TUNER_HAL_ERROR_UNKNOWN_FAILURE */
|
||||||
|
case 2: /* TUNER_HAL_ERROR_BUFFER_TOO_LARGE */
|
||||||
|
case 3: /* TUNER_HAL_ERROR_NOT_IMPLEMENTED */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
oemcrypto/opk/ports/linux/cas/ree/tuner_ree_serialization.h
Normal file
17
oemcrypto/opk/ports/linux/cas/ree/tuner_ree_serialization.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
#ifndef _TUNER_REE_SERIALIZATION_H_
|
||||||
|
#define _TUNER_REE_SERIALIZATION_H_
|
||||||
|
|
||||||
|
#include "tuner_hal.h"
|
||||||
|
|
||||||
|
ODK_Message OPK_Pack_TunerHal_Decrypt_Request(
|
||||||
|
const uint8_t* key_token, size_t key_token_length, KeyParityType key_parity,
|
||||||
|
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||||
|
|
||||||
|
void OPK_Unpack_TunerHal_Decrypt_Response(ODK_Message* msg,
|
||||||
|
TunerHalResult* result);
|
||||||
|
|
||||||
|
bool Is_Valid_TunerHalResult(uint32_t value);
|
||||||
|
|
||||||
|
#endif
|
||||||
21
oemcrypto/opk/ports/linux/cas/scripts/build.sh
Executable file
21
oemcrypto/opk/ports/linux/cas/scripts/build.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Builds OEMCrypto CAS demo test file and TA simulator
|
||||||
|
|
||||||
|
if [ -z "$CDM_DIR" ]; then
|
||||||
|
echo "CDM_DIR must be set to the top of the repo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# relative to CDM_DIR
|
||||||
|
PROJECT_DIR=./oemcrypto/opk/ports/linux/cas
|
||||||
|
|
||||||
|
build() {
|
||||||
|
pushd $CDM_DIR
|
||||||
|
make -j$(nproc) -C $PROJECT_DIR cas_unittests hello_world tee_simulator_cas $1
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
build PROVISIONING_METHOD=OEMCrypto_Keybox
|
||||||
|
|
||||||
|
# build PROVISIONING_METHOD=OEMCrypto_BootCertificateChain
|
||||||
|
|
||||||
43
oemcrypto/opk/ports/linux/cas/scripts/run.sh
Executable file
43
oemcrypto/opk/ports/linux/cas/scripts/run.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Runs OEMCrypto CAS demo test
|
||||||
|
#
|
||||||
|
# Race conditions sometimes occur, causing the executables to hang at the
|
||||||
|
# beginning of each test suite, so don't rely on these for CI/CD or production.
|
||||||
|
|
||||||
|
if [ -z "$CDM_DIR" ]; then
|
||||||
|
echo "CDM_DIR must be set to the top of the repo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
kill_ta_simulators() {
|
||||||
|
tee_simulator_cas_pid=$(ps aux | grep '[t]ee_simulator_cas' | awk '{print $2}')
|
||||||
|
|
||||||
|
if [ -n "$tee_simulator_cas_pid" ]; then
|
||||||
|
echo "Terminating CAS TEE simulator (PID $tee_simulator_cas_pid)"
|
||||||
|
kill $tee_simulator_cas_pid
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tests() {
|
||||||
|
builddir=$CDM_DIR/out/linux/cas
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$builddir/liboemcrypto:$builddir/libtuner
|
||||||
|
|
||||||
|
$builddir/tee_simulator_cas/tee_simulator_cas &
|
||||||
|
|
||||||
|
trap kill_ta_simulators EXIT
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
tee_simulator_cas_pid=$(ps aux | grep '[t]ee_simulator_cas' | awk '{print $2}')
|
||||||
|
if [[ -f "/proc/$tee_simulator_cas_pid/stat" ]]; then
|
||||||
|
$builddir/cas_unittests/cas_unittests --gtest_filter="*OEMCryptoCasDemoTest*"
|
||||||
|
# $builddir/hello_world/hello_world
|
||||||
|
else
|
||||||
|
echo "CAS TEE simulator did not start."
|
||||||
|
FINAL_RESULT=43
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tests
|
||||||
|
|
||||||
|
exit $FINAL_RESULT
|
||||||
64
oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/Makefile
Normal file
64
oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/Makefile
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This Makefile is not intended to be invoked on its own. It is possible
|
||||||
|
# though. Be sure to set the following variables.
|
||||||
|
# - CDM_DIR: path to top of CDM repo
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/cas/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/cas/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# Define this for tee-sources.mk, which uses it as a prefix for source file
|
||||||
|
# locations
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
# tee-sources.mk provides opk_base_ta_sources and opk_base_ta_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
# Definitions for wtpi_impl sources.mk
|
||||||
|
wtpi_impl_dir := $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl
|
||||||
|
|
||||||
|
# Provides wtpi_impl_sources and wtpi_impl_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/tee_simulator.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/clock.cpp \
|
||||||
|
$(tos_impl_dir)/tos_shared_memory.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tuner_tee_serialization.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/data_share_impl.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/tuner_impl.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas/wtpi_cas.c \
|
||||||
|
$(opk_base_ta_sources) \
|
||||||
|
$(wtpi_impl_sources) \
|
||||||
|
$(boringssl_sources) \
|
||||||
|
$(dice_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common \
|
||||||
|
$(OPK_REPO_TOP)/util/include \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee/tee_simulator_cas \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/cas/tee \
|
||||||
|
$(opk_base_ta_includes) \
|
||||||
|
$(wtpi_impl_includes) \
|
||||||
|
$(boringssl_includes) \
|
||||||
|
$(dice_includes) \
|
||||||
|
|
||||||
|
cflags += \
|
||||||
|
-DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \
|
||||||
|
-DSUPPORT_CAS \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"$(project)\" \
|
||||||
|
-D_DEFAULT_SOURCE
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -lpthread \
|
||||||
|
|
||||||
|
include ../../../rules.mk
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine License
|
||||||
|
Agreement. */
|
||||||
|
|
||||||
|
#ifndef _CAS_DATA_SHARE_H_
|
||||||
|
#define _CAS_DATA_SHARE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "wtpi_config_macros.h"
|
||||||
|
#include "wtpi_crypto_and_key_management_interface_layer1.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_NUMBER_OF_CAS_KEYTABLE_ENTRIES \
|
||||||
|
(CONTENT_KEYS_PER_SESSION * MAX_NUMBER_OF_ENTITLED_KEY_SESSIONS)
|
||||||
|
|
||||||
|
typedef uint32_t CasKeyDescriptor;
|
||||||
|
|
||||||
|
// Sets up key table. Returns false if already initialized.
|
||||||
|
// Called by OEMCrypto (writer)
|
||||||
|
bool CasKeyTable_Init();
|
||||||
|
|
||||||
|
// Tears down key table. Returns false if already uninitialized.
|
||||||
|
// Called by OEMCrypto (writer)
|
||||||
|
bool CasKeyTable_Close();
|
||||||
|
|
||||||
|
// Claims an empty key slot. Returns true if successful, false if unable to
|
||||||
|
// find an empty key slot. Writes a pointer to a CasKeyDescriptor object that
|
||||||
|
// can be used to reference the slot later.
|
||||||
|
// Returns false if key table not initialized.
|
||||||
|
// Called by OEMCrypto (writer)
|
||||||
|
bool CasKeyTable_ClaimSlot(CasKeyDescriptor** slot_descriptor);
|
||||||
|
|
||||||
|
// Writes a key and/or IV to a slot's even or odd space. If a key or IV has
|
||||||
|
// already been written, returns false.
|
||||||
|
// If WTPI_K1_SymmetricKey_Handle is NULL, it is ignored. If iv is NULL, it is
|
||||||
|
// ignored.
|
||||||
|
// Called by OEMCrypto (writer)
|
||||||
|
bool CasKeyTable_WriteKey(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
const WTPI_K1_SymmetricKey_Handle key,
|
||||||
|
OEMCryptoCipherMode cipher_mode);
|
||||||
|
bool CasKeyTable_WriteIV(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
const uint8_t* iv, size_t iv_length);
|
||||||
|
|
||||||
|
// Reads a key and iv from a slot's even or odd space. If a key or cipher mode
|
||||||
|
// have not been written yet, returns false. If an IV has not been written, then
|
||||||
|
// iv_length is set to 0 but this function returns true.
|
||||||
|
// Called by Tuner (reader)
|
||||||
|
bool CasKeyTable_Read(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
WTPI_K1_SymmetricKey_Handle* key,
|
||||||
|
OEMCryptoCipherMode* cipher_mode, uint8_t* iv,
|
||||||
|
size_t* iv_length);
|
||||||
|
|
||||||
|
// Converts a descriptor to a token. Tokens can be exported to the REE.
|
||||||
|
// Returns false if pointers are NULL or the conversion fails.
|
||||||
|
// Called by OEMCrypto
|
||||||
|
bool CasKeyTable_DescriptorToToken(CasKeyDescriptor descriptor, uint8_t* token,
|
||||||
|
size_t* token_length);
|
||||||
|
|
||||||
|
// Converts a token to a descriptor.
|
||||||
|
// Returns false if pointers are NULL or the conversion fails.
|
||||||
|
// Called by Tuner
|
||||||
|
bool CasKeyTable_TokenToDescriptor(const uint8_t* token, size_t token_length,
|
||||||
|
CasKeyDescriptor* descriptor);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/* 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 <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "data_share.h"
|
||||||
|
#include "oemcrypto_api_macros.h"
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K1_CopyKeyHandle(WTPI_K1_SymmetricKey_Handle key,
|
||||||
|
WTPI_K1_SymmetricKey_Handle* out);
|
||||||
|
|
||||||
|
typedef struct KeyData {
|
||||||
|
WTPI_K1_SymmetricKey_Handle key;
|
||||||
|
uint8_t iv[16];
|
||||||
|
OEMCryptoCipherMode cipher_mode;
|
||||||
|
bool key_written;
|
||||||
|
bool iv_written;
|
||||||
|
} KeyData;
|
||||||
|
|
||||||
|
typedef struct KeySlot {
|
||||||
|
KeyData even;
|
||||||
|
KeyData odd;
|
||||||
|
CasKeyDescriptor descriptor;
|
||||||
|
bool available;
|
||||||
|
} KeySlot;
|
||||||
|
|
||||||
|
typedef struct CasKeyTable {
|
||||||
|
KeySlot keys[MAX_NUMBER_OF_CAS_KEYTABLE_ENTRIES];
|
||||||
|
size_t next_free_index;
|
||||||
|
bool is_initialized;
|
||||||
|
} CasKeyTable;
|
||||||
|
|
||||||
|
static CasKeyTable g_cas_key_table = {0};
|
||||||
|
static pthread_mutex_t g_cas_key_table_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
// Convert CasKeyDescriptor to index into table
|
||||||
|
bool Helper_DescriptorToIndex(CasKeyDescriptor descriptor, size_t* index) {
|
||||||
|
size_t result = (uint32_t)descriptor;
|
||||||
|
if (result >= MAX_NUMBER_OF_CAS_KEYTABLE_ENTRIES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*index = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_DescriptorToToken(CasKeyDescriptor descriptor, uint8_t* token,
|
||||||
|
size_t* token_length) {
|
||||||
|
if (token == NULL || token_length == NULL) return false;
|
||||||
|
if (*token_length < sizeof(CasKeyDescriptor)) return false;
|
||||||
|
|
||||||
|
memcpy(token, &descriptor, sizeof(CasKeyDescriptor));
|
||||||
|
*token_length = sizeof(CasKeyDescriptor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_TokenToDescriptor(const uint8_t* token, size_t token_length,
|
||||||
|
CasKeyDescriptor* descriptor) {
|
||||||
|
if (token == NULL || descriptor == NULL ||
|
||||||
|
token_length != sizeof(CasKeyDescriptor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(descriptor, token, sizeof(CasKeyDescriptor));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boilerplate check to see if table is initialized (or not) before proceeding.
|
||||||
|
// Be sure to lock the global mutex before calling this.
|
||||||
|
#define CAS_RETURN_IF_INIT_IS(INITIALIZED) \
|
||||||
|
do { \
|
||||||
|
if (g_cas_key_table.is_initialized == INITIALIZED) { \
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
bool CasKeyTable_Init() {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(true);
|
||||||
|
|
||||||
|
memset(&g_cas_key_table, 0, sizeof(g_cas_key_table));
|
||||||
|
g_cas_key_table.is_initialized = true;
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_Close() {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(false);
|
||||||
|
|
||||||
|
memset(&g_cas_key_table, 0, sizeof(g_cas_key_table));
|
||||||
|
g_cas_key_table.is_initialized = false;
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_WriteKey(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
const WTPI_K1_SymmetricKey_Handle key,
|
||||||
|
OEMCryptoCipherMode cipher_mode) {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(false);
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
if (!Helper_DescriptorToIndex(descriptor, &index)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySlot* slot = &(g_cas_key_table.keys[index]);
|
||||||
|
KeyData* data = is_even ? &(slot->even) : &(slot->odd);
|
||||||
|
|
||||||
|
if (key != NULL) {
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle_copy;
|
||||||
|
OEMCryptoResult result = WTPI_K1_CopyKeyHandle(key, &key_handle_copy);
|
||||||
|
if (result!= OEMCrypto_SUCCESS) return false;
|
||||||
|
data->key = key_handle_copy;
|
||||||
|
data->cipher_mode = cipher_mode;
|
||||||
|
data->key_written = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_WriteIV(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
const uint8_t* iv, size_t iv_length) {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(false);
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
if (!Helper_DescriptorToIndex(descriptor, &index)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySlot* slot = &(g_cas_key_table.keys[index]);
|
||||||
|
KeyData* data = is_even ? &(slot->even) : &(slot->odd);
|
||||||
|
|
||||||
|
if (iv != NULL) {
|
||||||
|
if (iv_length > sizeof(data->iv)) {
|
||||||
|
// iv_length is too long
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(data->iv, iv, iv_length);
|
||||||
|
data->iv_written = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_Read(CasKeyDescriptor descriptor, bool is_even,
|
||||||
|
WTPI_K1_SymmetricKey_Handle* key,
|
||||||
|
OEMCryptoCipherMode* cipher_mode, uint8_t* iv,
|
||||||
|
size_t* iv_length) {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(false);
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
if (!Helper_DescriptorToIndex(descriptor, &index)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySlot* slot = &(g_cas_key_table.keys[index]);
|
||||||
|
KeyData* data = is_even ? &(slot->even) : &(slot->odd);
|
||||||
|
|
||||||
|
if (!data || !data->key_written) return false;
|
||||||
|
|
||||||
|
if (key == NULL) return false;
|
||||||
|
*key = data->key;
|
||||||
|
|
||||||
|
if (cipher_mode == NULL) return false;
|
||||||
|
*cipher_mode = data->cipher_mode;
|
||||||
|
|
||||||
|
if (data->iv_written) {
|
||||||
|
if (iv == NULL || iv_length == NULL) return false;
|
||||||
|
if (*iv_length < sizeof(data->iv)) {
|
||||||
|
*iv_length = sizeof(data->iv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(iv, data->iv, sizeof(data->iv));
|
||||||
|
*iv_length = sizeof(data->iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CasKeyTable_ClaimSlot(CasKeyDescriptor** slot_descriptor) {
|
||||||
|
pthread_mutex_lock(&g_cas_key_table_lock);
|
||||||
|
CAS_RETURN_IF_INIT_IS(false);
|
||||||
|
|
||||||
|
size_t i = g_cas_key_table.next_free_index;
|
||||||
|
if (i >= MAX_NUMBER_OF_CAS_KEYTABLE_ENTRIES) {
|
||||||
|
// out of space
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_cas_key_table.keys[i].descriptor = i;
|
||||||
|
*slot_descriptor = &(g_cas_key_table.keys[i].descriptor);
|
||||||
|
|
||||||
|
g_cas_key_table.next_free_index++;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&g_cas_key_table_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "odk_message.h"
|
||||||
|
#include "opk_dispatcher.h"
|
||||||
|
#include "opk_init.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "tuner_tee_serialization.h"
|
||||||
|
#include "tos_transport.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
|
||||||
|
static pthread_t main_thread_tid;
|
||||||
|
static bool thread_running = false;
|
||||||
|
|
||||||
|
void signalHandler(int signum) {
|
||||||
|
// TODO(fredgc): this doesn't actually kill anything because the main loop is
|
||||||
|
// stuck waiting for a new message.
|
||||||
|
thread_running = false;
|
||||||
|
// This exits, but then we skip the OPK_Terminate call.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request message data must be copied into a local buffer
|
||||||
|
// so the contents can't be modified while being parsed.
|
||||||
|
static uint8_t local_buffer[OPK_TRANSPORT_MESSAGE_SIZE];
|
||||||
|
|
||||||
|
static void* MainLoop(void* arg) {
|
||||||
|
OPK_Initialize();
|
||||||
|
thread_running = true;
|
||||||
|
while (thread_running) {
|
||||||
|
ODK_Message request, response;
|
||||||
|
OPK_TransportStatus transport_status =
|
||||||
|
TOS_Transport_ReceiveRequest(&request);
|
||||||
|
if (transport_status != OPK_TRANSPORT_STATUS_OK) {
|
||||||
|
LOGE("Receive request failed: status=%s",
|
||||||
|
OPK_TransportStatus_Str(transport_status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// !! IMPORTANT NOTE !!
|
||||||
|
// The request payload buffer MUST be copied out to TEE local
|
||||||
|
// storage so it can't be tampered with while being
|
||||||
|
// parsed. Failure to do so could introduce security
|
||||||
|
// vulnerabilities.
|
||||||
|
//
|
||||||
|
size_t payload_size = ODK_Message_GetSize(&request);
|
||||||
|
memcpy(local_buffer, ODK_Message_GetBase(&request), payload_size);
|
||||||
|
ODK_Message safe_request =
|
||||||
|
ODK_Message_Create(local_buffer, sizeof(local_buffer));
|
||||||
|
ODK_Message_SetSize(&safe_request, payload_size);
|
||||||
|
|
||||||
|
ODK_MessageStatus message_status =
|
||||||
|
OPK_DispatchMessage(&safe_request, &response);
|
||||||
|
if (message_status != MESSAGE_STATUS_OK) {
|
||||||
|
LOGE("Dispatch failed: status=%s", OPK_MessageStatus_Str(message_status));
|
||||||
|
// Try tuner-specific dispatch just to be sure
|
||||||
|
message_status = Tuner_DispatchMessage(&safe_request, &response);
|
||||||
|
|
||||||
|
if (message_status != MESSAGE_STATUS_OK) {
|
||||||
|
LOGE("Tuner dispatch failed: status=%s",
|
||||||
|
OPK_MessageStatus_Str(message_status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transport_status = TOS_Transport_SendResponse(&response);
|
||||||
|
if (transport_status != OPK_TRANSPORT_STATUS_OK) {
|
||||||
|
LOGE("Send response failed: status=%s",
|
||||||
|
OPK_TransportStatus_Str(transport_status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TOS_Transport_ReleaseMessage(&request);
|
||||||
|
TOS_Transport_ReleaseMessage(&response);
|
||||||
|
}
|
||||||
|
OPK_Terminate();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
pthread_attr_t p_attr;
|
||||||
|
|
||||||
|
int result = pthread_attr_init(&p_attr);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed pthread_attr_init: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("Reset shared resource state");
|
||||||
|
system("rm /dev/shm/*opk*");
|
||||||
|
|
||||||
|
LOGI("Starting the main loop thread");
|
||||||
|
result = pthread_create(&main_thread_tid, &p_attr, &MainLoop, nullptr);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed to spawn a thread: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
signal(SIGTERM, signalHandler);
|
||||||
|
LOGI("Main is waiting for the main loop thread to exit");
|
||||||
|
void* retval;
|
||||||
|
result = pthread_join(main_thread_tid, &retval);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed to join main thread: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "data_share.h"
|
||||||
|
#include "tuner_hal.h"
|
||||||
|
#include "wtpi_crypto_and_key_management_interface_layer1.h"
|
||||||
|
#include "wtpi_decrypt_sample_interface.h"
|
||||||
|
#include "wtpi_logging_interface.h"
|
||||||
|
|
||||||
|
// This Tuner_Decrypt implementation takes heavy advantage of the shared
|
||||||
|
// OEMCrypto and WTPI implementations in this demo. Since everything is
|
||||||
|
// compiled into the same binary, we have access to all the OEMCrypto helpers.
|
||||||
|
// For example, the key management is built in. A key handle created by the
|
||||||
|
// WTPI helpers is immediately usable since everything is in the same memory
|
||||||
|
// space. A separate Tuner TA would need to figure out how to make key handles
|
||||||
|
// portable from OEMCrypto.
|
||||||
|
|
||||||
|
TunerHalResult TunerHal_Decrypt(
|
||||||
|
const uint8_t* key_token, size_t key_token_length, KeyParityType key_parity,
|
||||||
|
const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||||
|
size_t samples_length, // the number of samples.
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||||
|
// Argument checks
|
||||||
|
if (key_token == NULL || samples == NULL || pattern == NULL) {
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (key_parity != TunerHal_KeyParityType_OddKey &&
|
||||||
|
key_parity != TunerHal_KeyParityType_EvenKey) {
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get key slot
|
||||||
|
CasKeyDescriptor descriptor;
|
||||||
|
if (!CasKeyTable_TokenToDescriptor(key_token, key_token_length,
|
||||||
|
&descriptor)) {
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn key slot data into key handle
|
||||||
|
bool is_even = key_parity == TunerHal_KeyParityType_EvenKey ? true : false;
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle = NULL;
|
||||||
|
uint8_t iv[16];
|
||||||
|
size_t iv_length = 16;
|
||||||
|
OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CTR; // default CTR
|
||||||
|
|
||||||
|
if (!CasKeyTable_Read(descriptor, is_even, &key_handle, &cipher_mode, iv,
|
||||||
|
&iv_length)) {
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < samples_length; i++) {
|
||||||
|
OPK_OutputBuffer output_buffer;
|
||||||
|
size_t output_offset;
|
||||||
|
if (OEMCrypto_SUCCESS !=
|
||||||
|
OPK_ParseDestBufferDesc(&samples[i].buffers.output_descriptor,
|
||||||
|
&output_buffer, &output_offset)) {
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: bounds check output buffer, check license limits, etc
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// This demo impl re-uses WTPI_DecryptSample to perform CTR decryption. This
|
||||||
|
// uses the SampleDescription IV instead of the entitled key IV. Since the
|
||||||
|
// incoming sample description is const, we have to modify it before
|
||||||
|
// calling TunerHal_Decrypt() for this demo.
|
||||||
|
OEMCryptoResult res =
|
||||||
|
WTPI_DecryptSample(key_handle, &samples[i], pattern, &output_buffer,
|
||||||
|
output_offset, cipher_mode);
|
||||||
|
if (res != OEMCrypto_SUCCESS) {
|
||||||
|
LOGE("Decrypt returned %d", res);
|
||||||
|
return TUNER_HAL_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TUNER_HAL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/* 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 <string.h>
|
||||||
|
#include "data_share.h"
|
||||||
|
#include "oemcrypto_check_macros.h"
|
||||||
|
#include "wtpi_cas_interface.h"
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InitializeCas(void) {
|
||||||
|
if (!CasKeyTable_Init()) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_TerminateCas(void) {
|
||||||
|
if (!CasKeyTable_Close()) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_AllocateKeySlotDescriptor(OEMCrypto_SESSION session_id,
|
||||||
|
void** key_slot_descriptor) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_slot_descriptor);
|
||||||
|
|
||||||
|
// Rely on CasKeyTable_ClaimSlot() using a pre allocated table, return pointer
|
||||||
|
// to descriptor in table key slot
|
||||||
|
CasKeyDescriptor* descriptor = NULL;
|
||||||
|
if (!CasKeyTable_ClaimSlot(&descriptor)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
*key_slot_descriptor = descriptor;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_FreeKeySlotDescriptor(void* key_slot_descriptor) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_slot_descriptor);
|
||||||
|
|
||||||
|
// Do nothing
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentKey(void* key_slot_descriptor,
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle,
|
||||||
|
OEMCryptoCipherMode cipher_mode,
|
||||||
|
bool is_even) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_slot_descriptor);
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_handle);
|
||||||
|
CasKeyDescriptor* descriptor = (CasKeyDescriptor*)key_slot_descriptor;
|
||||||
|
if (!CasKeyTable_WriteKey(*descriptor, is_even, key_handle, cipher_mode)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentIV(void* key_slot_descriptor, uint8_t* iv,
|
||||||
|
size_t iv_length, bool is_even) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_slot_descriptor);
|
||||||
|
RETURN_INVALID_CONTEXT_IF_ZERO(iv_length);
|
||||||
|
|
||||||
|
CasKeyDescriptor* descriptor = (CasKeyDescriptor*)key_slot_descriptor;
|
||||||
|
if (!CasKeyTable_WriteIV(*descriptor, is_even, iv, iv_length)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetKeyToken(void* key_slot_descriptor, uint8_t* key_token,
|
||||||
|
size_t* key_token_length) {
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_slot_descriptor);
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_token);
|
||||||
|
RETURN_INVALID_CONTEXT_IF_NULL(key_token_length);
|
||||||
|
|
||||||
|
size_t required_size = WTPI_GetKeyTokenSize();
|
||||||
|
|
||||||
|
if (*key_token_length < required_size) {
|
||||||
|
*key_token_length = required_size;
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*key_token_length = required_size;
|
||||||
|
CasKeyDescriptor* descriptor = (CasKeyDescriptor*)key_slot_descriptor;
|
||||||
|
if (!CasKeyTable_DescriptorToToken(*descriptor, key_token,
|
||||||
|
key_token_length)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_GetKeyTokenSize(void) { return sizeof(CasKeyDescriptor); }
|
||||||
153
oemcrypto/opk/ports/linux/cas/tee/tuner_tee_serialization.c
Normal file
153
oemcrypto/opk/ports/linux/cas/tee/tuner_tee_serialization.c
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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 <inttypes.h>
|
||||||
|
|
||||||
|
#include "GEN_common_serializer.h"
|
||||||
|
#include "GEN_tee_serializer.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "bump_allocator.h"
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "marshaller_base.h"
|
||||||
|
#include "message_debug.h"
|
||||||
|
#include "odk_overflow.h"
|
||||||
|
#include "oemcrypto_wall_clock.h"
|
||||||
|
#include "opk_dispatcher.h"
|
||||||
|
|
||||||
|
#include "shared_buffer_allocator.h"
|
||||||
|
#include "tee_special_cases.h"
|
||||||
|
#include "tos_shared_memory_interface.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
|
||||||
|
#include "tuner_tee_serialization.h"
|
||||||
|
|
||||||
|
static ODK_Message CreateEmptyMessage(void) {
|
||||||
|
static uint8_t buffer[1];
|
||||||
|
ODK_Message msg = ODK_Message_Create(buffer, sizeof(buffer));
|
||||||
|
OPK_PackEOM(&msg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ODK_Message NullMessage(void) { return ODK_Message_Create(NULL, 0); }
|
||||||
|
|
||||||
|
void OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
|
||||||
|
OEMCrypto_CENCEncryptPatternDesc* obj);
|
||||||
|
|
||||||
|
/* See opk_dispatcher.h for definition of OPK_DispatchMessage() */
|
||||||
|
ODK_MessageStatus Tuner_DispatchMessage(ODK_Message* request,
|
||||||
|
ODK_Message* response) {
|
||||||
|
if (request == NULL || response == NULL)
|
||||||
|
return MESSAGE_STATUS_NULL_POINTER_ERROR;
|
||||||
|
*response = NullMessage();
|
||||||
|
uint32_t api_value;
|
||||||
|
OPK_Unpack_uint32_t(request, &api_value);
|
||||||
|
uint64_t timestamp;
|
||||||
|
OPK_Unpack_uint64_t(request, ×tamp);
|
||||||
|
OPK_SetWallClockTime(timestamp);
|
||||||
|
OPK_BumpAllocator_Reset();
|
||||||
|
OPK_SharedBuffer_Reset();
|
||||||
|
ODK_Message_Reset(request);
|
||||||
|
switch (api_value) {
|
||||||
|
case 12345: /* TunerHal_Decrypt */
|
||||||
|
size_t key_token_length;
|
||||||
|
OPK_Init_size_t((size_t*)&key_token_length);
|
||||||
|
size_t* wrapped_key_token_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
|
||||||
|
OPK_Init_size_t(wrapped_key_token_length);
|
||||||
|
uint8_t* key_token;
|
||||||
|
OPK_InitPointer((uint8_t**)&key_token);
|
||||||
|
KeyParityType key_parity;
|
||||||
|
OPK_Init_uint32_t((uint32_t*)&key_parity);
|
||||||
|
size_t samples_length;
|
||||||
|
OPK_Init_size_t((size_t*)&samples_length);
|
||||||
|
OEMCrypto_SampleDescription* samples;
|
||||||
|
OPK_InitPointer((uint8_t**)&samples);
|
||||||
|
OEMCrypto_CENCEncryptPatternDesc* pattern =
|
||||||
|
(OEMCrypto_CENCEncryptPatternDesc*)OPK_VarAlloc(
|
||||||
|
sizeof(OEMCrypto_CENCEncryptPatternDesc));
|
||||||
|
OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
|
||||||
|
(OEMCrypto_CENCEncryptPatternDesc*)pattern);
|
||||||
|
// OPK_Unpack_DecryptCENC_Request(request, &session, &samples,
|
||||||
|
// &samples_length, &pattern);
|
||||||
|
OPK_Unpack_TunerHal_Decrypt_Request(request, &key_token,
|
||||||
|
&key_token_length, &key_parity,
|
||||||
|
&samples, &samples_length, &pattern);
|
||||||
|
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
|
||||||
|
TunerHalResult result;
|
||||||
|
OPK_Init_uint32_t((uint32_t*)&result);
|
||||||
|
result = TunerHal_Decrypt(key_token, key_token_length, key_parity,
|
||||||
|
samples, samples_length, pattern);
|
||||||
|
*response = OPK_Pack_TunerHal_Decrypt_Response(result);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return MESSAGE_STATUS_API_VALUE_ERROR;
|
||||||
|
}
|
||||||
|
return ODK_Message_GetStatus(response);
|
||||||
|
|
||||||
|
handle_invalid_request:
|
||||||
|
LOGE("invalid request");
|
||||||
|
*response = CreateEmptyMessage();
|
||||||
|
return MESSAGE_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPK_Unpack_TunerHal_Decrypt_Request(
|
||||||
|
ODK_Message* msg, uint8_t** key_token, size_t* key_token_length,
|
||||||
|
KeyParityType* key_parity, OEMCrypto_SampleDescription** samples,
|
||||||
|
size_t* samples_length, OEMCrypto_CENCEncryptPatternDesc** pattern) {
|
||||||
|
uint32_t api_value = UINT32_MAX;
|
||||||
|
OPK_Unpack_uint32_t(msg, &api_value);
|
||||||
|
if (api_value != 12345)
|
||||||
|
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
|
||||||
|
uint64_t timestamp;
|
||||||
|
OPK_Unpack_uint64_t(msg, ×tamp);
|
||||||
|
|
||||||
|
OPK_Unpack_size_t(msg, key_token_length);
|
||||||
|
OPK_UnpackInPlace(msg, (uint8_t**)key_token,
|
||||||
|
OPK_FromSizeTPtr(key_token_length));
|
||||||
|
OPK_Unpack_uint32_t(msg, key_parity);
|
||||||
|
|
||||||
|
OPK_Unpack_size_t(msg, samples_length);
|
||||||
|
/* unpack object array with unpacker function
|
||||||
|
* OPK_Unpack_OEMCrypto_SampleDescription */
|
||||||
|
ODK_Message* odk_message = msg;
|
||||||
|
void** address = (void**)samples;
|
||||||
|
LengthType count = OPK_FromSizeTPtr(samples_length);
|
||||||
|
size_t size = sizeof(OEMCrypto_SampleDescription);
|
||||||
|
if (address) {
|
||||||
|
*address = NULL;
|
||||||
|
}
|
||||||
|
if (!OPK_UnpackIsNull(odk_message)) {
|
||||||
|
if (address && !OPK_LengthIsNull(count)) {
|
||||||
|
size_t bytes_to_unpack = 0;
|
||||||
|
if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) {
|
||||||
|
ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR);
|
||||||
|
} else {
|
||||||
|
*address = OPK_BumpAllocate(bytes_to_unpack);
|
||||||
|
if (!*address) {
|
||||||
|
ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY);
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < OPK_ToSizeT(count); i++) {
|
||||||
|
OPK_Unpack_OEMCrypto_SampleDescription(
|
||||||
|
odk_message,
|
||||||
|
(OEMCrypto_SampleDescription*)((*address) + size * i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OPK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc(msg, pattern);
|
||||||
|
OPK_UnpackEOM(msg);
|
||||||
|
OPK_SharedBuffer_FinalizeUnpacking();
|
||||||
|
}
|
||||||
|
|
||||||
|
ODK_Message OPK_Pack_TunerHal_Decrypt_Response(TunerHalResult result) {
|
||||||
|
uint32_t api_value = 12345; /* from _oecc8 */
|
||||||
|
ODK_Message msg = TOS_Transport_GetResponse();
|
||||||
|
OPK_Pack_uint32_t(&msg, &api_value);
|
||||||
|
OPK_Pack_uint32_t(&msg, &result);
|
||||||
|
OPK_PackEOM(&msg);
|
||||||
|
OPK_SharedBuffer_FinalizePacking();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
27
oemcrypto/opk/ports/linux/cas/tee/tuner_tee_serialization.h
Normal file
27
oemcrypto/opk/ports/linux/cas/tee/tuner_tee_serialization.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef TUNER_TEE_SERIALIZER_H_
|
||||||
|
#define TUNER_TEE_SERIALIZER_H_
|
||||||
|
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "opk_serialization_base.h"
|
||||||
|
#include "tuner_hal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ODK_Message OPK_Pack_TunerHal_Decrypt_Response(TunerHalResult result);
|
||||||
|
void OPK_Unpack_TunerHal_Decrypt_Request(
|
||||||
|
ODK_Message* msg, uint8_t** key_token, size_t* key_token_length,
|
||||||
|
KeyParityType* key_parity, OEMCrypto_SampleDescription** samples,
|
||||||
|
size_t* samples_length, OEMCrypto_CENCEncryptPatternDesc** pattern);
|
||||||
|
|
||||||
|
// void OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
|
||||||
|
// OEMCrypto_CENCEncryptPatternDesc* obj);
|
||||||
|
|
||||||
|
/* See opk_dispatcher.h for definition of OPK_DispatchMessage() */
|
||||||
|
ODK_MessageStatus Tuner_DispatchMessage(ODK_Message* request,
|
||||||
|
ODK_Message* response);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif /* TUNER_TEE_SERIALIZER_H_ */
|
||||||
40
oemcrypto/opk/ports/linux/cas/tuner_hal.h
Normal file
40
oemcrypto/opk/ports/linux/cas/tuner_hal.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine License
|
||||||
|
Agreement. */
|
||||||
|
|
||||||
|
#ifndef _TUNER_HAL_H_
|
||||||
|
#define _TUNER_HAL_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum TunerHalResult {
|
||||||
|
TUNER_HAL_SUCCESS = 0,
|
||||||
|
TUNER_HAL_ERROR_UNKNOWN_FAILURE = 1,
|
||||||
|
TUNER_HAL_ERROR_BUFFER_TOO_LARGE = 2,
|
||||||
|
TUNER_HAL_ERROR_NOT_IMPLEMENTED = 3,
|
||||||
|
} TunerHalResult;
|
||||||
|
|
||||||
|
typedef enum KeyParityType {
|
||||||
|
TunerHal_KeyParityType_NotEncrypted, // Should never be used.
|
||||||
|
TunerHal_KeyParityType_OddKey,
|
||||||
|
TunerHal_KeyParityType_EvenKey,
|
||||||
|
TunerHal_KeyParityType_MaxValue = TunerHal_KeyParityType_EvenKey,
|
||||||
|
} KeyParityType;
|
||||||
|
|
||||||
|
TunerHalResult TunerHal_Decrypt(
|
||||||
|
const uint8_t* key_token, size_t key_token_length, KeyParityType key_parity,
|
||||||
|
const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||||
|
size_t samples_length, // the number of samples.
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
19
oemcrypto/opk/ports/linux/common/posix_resources.h
Normal file
19
oemcrypto/opk/ports/linux/common/posix_resources.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
|
||||||
|
#ifndef POSIX_RESOURCES__H_
|
||||||
|
#define POSIX_RESOURCES__H_
|
||||||
|
|
||||||
|
#include "posix_services.h"
|
||||||
|
|
||||||
|
// Global allocation of posix shared memory and semaphore
|
||||||
|
// resources for the transport and shared memory buffers
|
||||||
|
|
||||||
|
typedef posix::SharedMemory<0> RequestResponseBlock;
|
||||||
|
typedef posix::SharedMemory<1> MailboxBlock;
|
||||||
|
typedef posix::SharedMemory<2> SerializationBlock;
|
||||||
|
typedef posix::Semaphore<0> RequestSemaphore;
|
||||||
|
typedef posix::Semaphore<1> ResponseSemaphore;
|
||||||
|
|
||||||
|
#endif // POSIX_RESOURCES__H_
|
||||||
136
oemcrypto/opk/ports/linux/common/posix_services.h
Normal file
136
oemcrypto/opk/ports/linux/common/posix_services.h
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
|
||||||
|
#ifndef LINUX_IPC_POSIX_SERVICES_H_
|
||||||
|
#define LINUX_IPC_POSIX_SERVICES_H_
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "log_macros.h"
|
||||||
|
|
||||||
|
#ifndef WV_POSIX_RESOURCE_ID
|
||||||
|
# define WV_POSIX_RESOURCE_ID "tee-sim"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace posix {
|
||||||
|
|
||||||
|
// Services for shared memory and semaphores layered on the POSIX
|
||||||
|
// shm_* and sem_* functions
|
||||||
|
|
||||||
|
// The Semaphore class is used to synchronize execution across process
|
||||||
|
// boundaries using the POSIX semaphore lib. N is an integer
|
||||||
|
// identifying the semaphore instance.
|
||||||
|
class Resource {
|
||||||
|
public:
|
||||||
|
Resource(const std::string& name, const std::string& posix_prefix)
|
||||||
|
: dev_path_("/dev/shm/" + posix_prefix + WV_POSIX_RESOURCE_ID + name),
|
||||||
|
posix_name_("/" WV_POSIX_RESOURCE_ID + name) {}
|
||||||
|
~Resource() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const std::string dev_path_;
|
||||||
|
const std::string posix_name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class Semaphore : public Resource {
|
||||||
|
public:
|
||||||
|
Semaphore() : Resource("opk-" + std::to_string(N), "sem."), sem_(nullptr) {
|
||||||
|
sem_ = sem_open(posix_name_.c_str(), O_CREAT, 0600, 0);
|
||||||
|
if (!sem_) {
|
||||||
|
LOGE("failed to open semaphore %s", posix_name_.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Semaphore() {
|
||||||
|
if (sem_) {
|
||||||
|
sem_close(sem_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void post() {
|
||||||
|
if (sem_) sem_post(sem_);
|
||||||
|
}
|
||||||
|
void wait() {
|
||||||
|
if (sem_) sem_wait(sem_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sem_t* sem_;
|
||||||
|
|
||||||
|
Semaphore(const Semaphore&) = delete;
|
||||||
|
void operator=(const Semaphore&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Manage blocks of shared memory across process boundaries using
|
||||||
|
// the POSIX shared memory functions. N is an integer identifying the
|
||||||
|
// shared memory block.
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class SharedMemory : public Resource {
|
||||||
|
public:
|
||||||
|
SharedMemory()
|
||||||
|
: Resource("opk-shm-" + std::to_string(N), ""),
|
||||||
|
fd_(-1),
|
||||||
|
address_(nullptr),
|
||||||
|
size_(0) {
|
||||||
|
Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedMemory() { Close(); }
|
||||||
|
|
||||||
|
uint8_t* GetAddress() const { return address_; }
|
||||||
|
size_t GetSize() const { return size_; }
|
||||||
|
|
||||||
|
bool Allocate(size_t size) {
|
||||||
|
if (fd_ == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ftruncate(fd_, size) == -1) {
|
||||||
|
LOGE("failed to set shared memory %s to size %zd: %s", dev_path_.c_str(),
|
||||||
|
size_, strerror(errno));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
address_ = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, fd_, 0);
|
||||||
|
if (address_ == nullptr) {
|
||||||
|
LOGE("mmap of size %zu failed: %s", size, strerror(errno));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
size_ = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fd_;
|
||||||
|
uint8_t* address_;
|
||||||
|
size_t size_;
|
||||||
|
|
||||||
|
void Open() { fd_ = shm_open(posix_name_.c_str(), O_CREAT | O_RDWR, 0600); }
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
if (address_) {
|
||||||
|
munmap(address_, size_);
|
||||||
|
address_ = nullptr;
|
||||||
|
size_ = 0;
|
||||||
|
}
|
||||||
|
if (fd_ != -1) {
|
||||||
|
close(fd_);
|
||||||
|
fd_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemory(const SharedMemory&) = delete;
|
||||||
|
void operator=(const SharedMemory&) = delete;
|
||||||
|
};
|
||||||
|
}; // namespace posix
|
||||||
|
|
||||||
|
#endif /* LINUX_IPC_POSIX_SERVICES_H_ */
|
||||||
237
oemcrypto/opk/ports/linux/common/test/shared_memory_test.cpp
Normal file
237
oemcrypto/opk/ports/linux/common/test/shared_memory_test.cpp
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "posix_services.h"
|
||||||
|
#include "tos_shared_memory_interface.h"
|
||||||
|
#include "tos_transport.h"
|
||||||
|
|
||||||
|
using namespace posix;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Entry point for the TEE process
|
||||||
|
*/
|
||||||
|
static void RunTEE();
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc == 2) {
|
||||||
|
if (*argv[1] == '1') {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
} else {
|
||||||
|
RunTEE();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fork()) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
} else {
|
||||||
|
RunTEE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility functions shared by REE and TEE
|
||||||
|
static const unsigned KiB = 1024;
|
||||||
|
static const unsigned MiB = KiB * 1024;
|
||||||
|
|
||||||
|
static uint8_t test_buffer[1024];
|
||||||
|
|
||||||
|
/* rand() seed for FillMemory/TestMemory, needs to be the same in REE and TEE */
|
||||||
|
unsigned seed = 1234;
|
||||||
|
|
||||||
|
/* Utility functions common to REE and TEE */
|
||||||
|
void FillMemory(uint8_t* addr, size_t length, unsigned seed) {
|
||||||
|
std::srand(seed);
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
addr[i] = static_cast<uint8_t>(std::rand() & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestMemory(uint8_t* addr, size_t length, unsigned seed) {
|
||||||
|
std::srand(seed);
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
if (addr[i] != static_cast<uint8_t>(std::rand() & 0xff)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestZero(uint8_t* addr, size_t length) {
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
if (addr[i] != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* GetAddress() { return TOS_SharedMemory_GetAddress(); }
|
||||||
|
size_t GetSize() { return TOS_SharedMemory_GetSize(); }
|
||||||
|
|
||||||
|
class SharedMemoryInterfaceTest : public testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {}
|
||||||
|
void TearDown() override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map sizes must meet the minum requirements
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, AvailableSize) {
|
||||||
|
EXPECT_LE(2 * MiB + 32 * KiB, TOS_SharedMemory_AvailableSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure everything starts out initialized
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, InitialState) {
|
||||||
|
EXPECT_EQ(nullptr, GetAddress());
|
||||||
|
EXPECT_EQ(0, GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block with a 1 KiB size
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, Allocate1KiBSize) {
|
||||||
|
size_t size = 1 * KiB;
|
||||||
|
TOS_SharedMemory_Allocate(size);
|
||||||
|
EXPECT_NE(nullptr, GetAddress());
|
||||||
|
EXPECT_EQ(size, GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the block with a 1 KiB size and make sure
|
||||||
|
// we can read/write it
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, AllocateAllWith1KiBSizeAndRead) {
|
||||||
|
size_t size = 1 * KiB;
|
||||||
|
TOS_SharedMemory_Allocate(size);
|
||||||
|
FillMemory(GetAddress(), size, seed);
|
||||||
|
EXPECT_TRUE(TestMemory(GetAddress(), size, seed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test releasing the block
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, Release) {
|
||||||
|
size_t size = 1 * KiB;
|
||||||
|
TOS_SharedMemory_Allocate(size);
|
||||||
|
EXPECT_NE(nullptr, GetAddress());
|
||||||
|
TOS_SharedMemory_Release();
|
||||||
|
// all released?
|
||||||
|
EXPECT_EQ(nullptr, GetAddress());
|
||||||
|
EXPECT_EQ(0, GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block with zero size
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, AllocateZeroSize) {
|
||||||
|
size_t size = 0;
|
||||||
|
TOS_SharedMemory_Allocate(size);
|
||||||
|
EXPECT_NE(nullptr, GetAddress());
|
||||||
|
EXPECT_EQ(size, GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block with the declared available size
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, AllocateToAvailableSize) {
|
||||||
|
size_t size = TOS_SharedMemory_AvailableSize();
|
||||||
|
TOS_SharedMemory_Allocate(size);
|
||||||
|
EXPECT_NE(nullptr, GetAddress());
|
||||||
|
EXPECT_EQ(size, GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block and see if it will copy in from REE address on
|
||||||
|
// finalization.
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, CopyIn) {
|
||||||
|
// fill test buffer
|
||||||
|
FillMemory(&test_buffer[0], sizeof(test_buffer), seed);
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
OPK_SharedMemory_CopyVector copy_vec = {
|
||||||
|
.address = &test_buffer[0], .offset = 0, .length = sizeof(test_buffer)};
|
||||||
|
TOS_SharedMemory_Finalize(©_vec, 1, NULL, 0);
|
||||||
|
EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block and ee if it will copy in from REE address on
|
||||||
|
// finalization at a non-zero offset.
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, CopyInAtOffset) {
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
// Fill the test buffer and zero out the block
|
||||||
|
FillMemory(&test_buffer[0], sizeof(test_buffer), seed);
|
||||||
|
memset(GetAddress(), 0, sizeof(test_buffer));
|
||||||
|
// copy in the first 512 bytes of the test_buffer into the
|
||||||
|
// shared memory block at offset 128, leaving the rest as zeros.
|
||||||
|
OPK_SharedMemory_CopyVector copy_vec = {
|
||||||
|
.address = &test_buffer[0], .offset = 128, .length = 512};
|
||||||
|
TOS_SharedMemory_Finalize(©_vec, 1, NULL, 0);
|
||||||
|
EXPECT_TRUE(TestMemory(GetAddress() + 128, 512, seed));
|
||||||
|
EXPECT_TRUE(TestZero(GetAddress(), 128));
|
||||||
|
EXPECT_TRUE(TestZero(GetAddress() + 640, sizeof(test_buffer) - 640));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block with a non-NULL address and 1KiB size. See if it
|
||||||
|
// will copy out to REE address on finalization.
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, CopyOut) {
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
// fill shared memory block
|
||||||
|
FillMemory(GetAddress(), sizeof(test_buffer), seed);
|
||||||
|
memset(&test_buffer[0], 0, sizeof(test_buffer));
|
||||||
|
OPK_SharedMemory_CopyVector copy_vec = {
|
||||||
|
.address = &test_buffer[0], .offset = 0, .length = sizeof(test_buffer)};
|
||||||
|
TOS_SharedMemory_Finalize(NULL, 0, ©_vec, 1);
|
||||||
|
EXPECT_TRUE(TestMemory(&test_buffer[0], sizeof(test_buffer), seed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a block and see if it will copy out from REE address on
|
||||||
|
// finalization at a non-zero offset.
|
||||||
|
TEST_F(SharedMemoryInterfaceTest, CopyOutAtOffset) {
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
// fill test buffer
|
||||||
|
FillMemory(&test_buffer[0], sizeof(test_buffer), seed);
|
||||||
|
|
||||||
|
// Zero out the shared memory block, fill 512 bytes of the shared
|
||||||
|
// memory block at offset 128 and zero out the test_buffer
|
||||||
|
memset(GetAddress(), 0, sizeof(test_buffer));
|
||||||
|
FillMemory(GetAddress() + 128, 512, seed);
|
||||||
|
memset(&test_buffer[0], 0, sizeof(test_buffer));
|
||||||
|
|
||||||
|
// copy out 512 bytes of the shared memory block at offset
|
||||||
|
// 128 into the test buffer
|
||||||
|
OPK_SharedMemory_CopyVector copy_vec = {
|
||||||
|
.address = &test_buffer[0], .offset = 128, .length = 512};
|
||||||
|
TOS_SharedMemory_Finalize(NULL, 0, ©_vec, 1);
|
||||||
|
EXPECT_TRUE(TestMemory(&test_buffer[0], 512, seed));
|
||||||
|
EXPECT_TRUE(TestZero(&test_buffer[512], sizeof(test_buffer) - 512));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The IPC_SharedMemoryTests make sure that shared memory actually works
|
||||||
|
// across processes.
|
||||||
|
|
||||||
|
class SharedMemoryIPCTest : public SharedMemoryInterfaceTest {};
|
||||||
|
|
||||||
|
// Test TEE->REE and REE->TEE on a block
|
||||||
|
TEST_F(SharedMemoryIPCTest, SharedAccess) {
|
||||||
|
Semaphore<0> begin;
|
||||||
|
Semaphore<1> ree_filled;
|
||||||
|
Semaphore<2> tee_filled;
|
||||||
|
Semaphore<3> ree_done;
|
||||||
|
begin.post();
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
FillMemory(GetAddress(), sizeof(test_buffer), seed);
|
||||||
|
ree_filled.post();
|
||||||
|
tee_filled.wait();
|
||||||
|
EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed + 1));
|
||||||
|
ree_done.post();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RunTEE() {
|
||||||
|
/* SharedAccess test */
|
||||||
|
Semaphore<0> begin;
|
||||||
|
Semaphore<1> ree_filled;
|
||||||
|
Semaphore<2> tee_filled;
|
||||||
|
Semaphore<3> ree_done;
|
||||||
|
begin.wait();
|
||||||
|
TOS_SharedMemory_Allocate(sizeof(test_buffer));
|
||||||
|
ree_filled.wait();
|
||||||
|
EXPECT_TRUE(TestMemory(GetAddress(), sizeof(test_buffer), seed));
|
||||||
|
FillMemory(GetAddress(), sizeof(test_buffer), seed + 1);
|
||||||
|
tee_filled.post();
|
||||||
|
ree_done.wait();
|
||||||
|
}
|
||||||
28
oemcrypto/opk/ports/linux/common/test/shared_memory_test.gyp
Normal file
28
oemcrypto/opk/ports/linux/common/test/shared_memory_test.gyp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
'includes' : {
|
||||||
|
'../../../../serialization/settings.gypi',
|
||||||
|
},
|
||||||
|
'target_defaults': {
|
||||||
|
'include_dirs' : [
|
||||||
|
'.',
|
||||||
|
'..',
|
||||||
|
'<(third_party_dir)/googletest/googletest/include',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets' : [
|
||||||
|
{
|
||||||
|
'target_name': 'shared_memory_test',
|
||||||
|
'type': 'executable',
|
||||||
|
'sources': [
|
||||||
|
'shared_memory_test.cpp',
|
||||||
|
'../tos_shared_memory.cpp',
|
||||||
|
'../tos_logging.cpp',
|
||||||
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'<(third_party_dir)/googletest.gyp:gtest',
|
||||||
|
'<(serialization_dir)/tee/tee.gyp:opk_tee',
|
||||||
|
],
|
||||||
|
'libraries': ['-lrt', '-lpthread', '-ldl'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
68
oemcrypto/opk/ports/linux/common/tos_logging.cpp
Normal file
68
oemcrypto/opk/ports/linux/common/tos_logging.cpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is an implementation of the tos_logging_interface for
|
||||||
|
// the linux trusted OS simulator port of OPK. For both the REE and
|
||||||
|
// TEE, it just writes the output to stderr.
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "tos_logging_interface.h"
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* See "tos_logging_interface.h" for documentation of TOS_Log.
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
static const char* LevelString(OPK_LogLevel level) {
|
||||||
|
switch (level) {
|
||||||
|
case OPK_LogLevel_Fatal:
|
||||||
|
return "FATAL";
|
||||||
|
case OPK_LogLevel_Error:
|
||||||
|
return "ERROR";
|
||||||
|
case OPK_LogLevel_Warning:
|
||||||
|
return "WARNING";
|
||||||
|
case OPK_LogLevel_Info:
|
||||||
|
return "INFO";
|
||||||
|
case OPK_LogLevel_Debug:
|
||||||
|
return "DEBUG";
|
||||||
|
case OPK_LogLevel_Verbose:
|
||||||
|
return "VERBOSE";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__((format(printf, 5, 6)))
|
||||||
|
#endif
|
||||||
|
void TOS_Log(const char* file, const char* func, int line,
|
||||||
|
OPK_LogLevel level, const char* fmt, ...) {
|
||||||
|
/*
|
||||||
|
* By default, messages with levels at or higher than min_log_level
|
||||||
|
* will be logged. You can change the defaulit value of
|
||||||
|
* min_log_level here at compile time, or set the environment
|
||||||
|
* variable LINUX_IPC_LOG_LEVEL to the integer value of the minimum
|
||||||
|
* log level desired at runtime.
|
||||||
|
*/
|
||||||
|
static OPK_LogLevel min_log_level = OPK_LogLevel_Warning;
|
||||||
|
static bool set_log_level = true;
|
||||||
|
if (set_log_level) {
|
||||||
|
const char* env_level = getenv("LINUX_IPC_LOG_LEVEL");
|
||||||
|
if (env_level) {
|
||||||
|
min_log_level = static_cast<OPK_LogLevel>(atoi(env_level));
|
||||||
|
}
|
||||||
|
set_log_level = false;
|
||||||
|
}
|
||||||
|
if (level >= min_log_level) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
fprintf(stderr, "[%s:%s(%d):%s] ", LevelString(level), file, line, func);
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
oemcrypto/opk/ports/linux/common/tos_secure_buffers.c
Normal file
34
oemcrypto/opk/ports/linux/common/tos_secure_buffers.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
#include "opk_serialization_base.h"
|
||||||
|
#include "tos_secure_buffer_interface.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The simulator doesn't do anything special with secure buffers,
|
||||||
|
* just pass the fields through unmodified
|
||||||
|
*/
|
||||||
|
|
||||||
|
void TOS_SecureBuffer_Pack(ODK_Message* message,
|
||||||
|
const OEMCrypto_DestBufferDesc* obj) {
|
||||||
|
/* secure memory - pack handle, length, offset */
|
||||||
|
OPK_Pack_uint64_t(message,
|
||||||
|
(const uint64_t*)&obj->buffer.secure.secure_buffer);
|
||||||
|
OPK_Pack_size_t(message, &obj->buffer.secure.secure_buffer_length);
|
||||||
|
OPK_Pack_size_t(message, &obj->buffer.secure.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TOS_SecureBuffer_Unpack(ODK_Message* message,
|
||||||
|
OEMCrypto_DestBufferDesc* obj) {
|
||||||
|
/* secure memory - unpack handle, length, offset */
|
||||||
|
OPK_Unpack_uint64_t(message, (uint64_t*)&obj->buffer.secure.secure_buffer);
|
||||||
|
OPK_Unpack_size_t(message, &obj->buffer.secure.secure_buffer_length);
|
||||||
|
OPK_Unpack_size_t(message, &obj->buffer.secure.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TOS_SecureBuffer_CheckSize(void* handle, size_t size) {
|
||||||
|
/* without real secure memory, there's nothing we can do here */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
88
oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp
Normal file
88
oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is an implementation of the tos_shared_memory_interface for
|
||||||
|
// the linux trusted OS simulator port of OPK. It uses the
|
||||||
|
// posix_services.h implementation of shared memory which is based on
|
||||||
|
// the POSIX shared memory library.
|
||||||
|
|
||||||
|
#include "posix_resources.h"
|
||||||
|
#include "tos_shared_memory_interface.h"
|
||||||
|
|
||||||
|
using namespace posix;
|
||||||
|
|
||||||
|
// shared memory for OEMCrypto parameters
|
||||||
|
static SerializationBlock* shared_memory_ = nullptr;
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* See "tos_shared_memory_interface.h" for documentation
|
||||||
|
* of each of the TOS_SharedMemory interface functions below.
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
bool TOS_SharedMemory_Allocate(size_t size) {
|
||||||
|
if (!shared_memory_) {
|
||||||
|
shared_memory_ = new SerializationBlock();
|
||||||
|
if (!shared_memory_) {
|
||||||
|
LOGE("Failed to initialize shared memory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!shared_memory_->Allocate(size)) {
|
||||||
|
LOGE("Failed to allocate shared memory of size %zd bytes", size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TOS_SharedMemory_Release(void) {
|
||||||
|
if (shared_memory_) {
|
||||||
|
delete shared_memory_;
|
||||||
|
shared_memory_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* TOS_SharedMemory_GetAddress(void) {
|
||||||
|
return shared_memory_ ? shared_memory_->GetAddress() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TOS_SharedMemory_GetSize(void) {
|
||||||
|
return shared_memory_ ? shared_memory_->GetSize() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TOS_SharedMemory_Finalize(OPK_SharedMemory_CopyVector* in_vec,
|
||||||
|
size_t in_count,
|
||||||
|
OPK_SharedMemory_CopyVector* out_vec,
|
||||||
|
size_t out_count) {
|
||||||
|
if (shared_memory_) {
|
||||||
|
uint8_t* address = shared_memory_->GetAddress();
|
||||||
|
if (address) {
|
||||||
|
for (size_t i = 0; i < in_count; i++) {
|
||||||
|
if (in_vec[i].address) {
|
||||||
|
memcpy(address + in_vec[i].offset, in_vec[i].address,
|
||||||
|
in_vec[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < out_count; i++) {
|
||||||
|
if (out_vec[i].address) {
|
||||||
|
memcpy(out_vec[i].address, address + out_vec[i].offset,
|
||||||
|
out_vec[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provide enough shared memory for the max sample size for input and
|
||||||
|
* output shared memory buffers plus serialization buffer
|
||||||
|
*/
|
||||||
|
size_t TOS_SharedMemory_AvailableSize(void) {
|
||||||
|
const size_t KiB = 1024;
|
||||||
|
const size_t MiB = 1024 * KiB;
|
||||||
|
const size_t max_sample_size = 4 * MiB;
|
||||||
|
const size_t serialization_buffer_size = 32 * KiB;
|
||||||
|
return 2 * max_sample_size + serialization_buffer_size;
|
||||||
|
}
|
||||||
155
oemcrypto/opk/ports/linux/common/tos_transport.cpp
Normal file
155
oemcrypto/opk/ports/linux/common/tos_transport.cpp
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is an implementation of the opk_transport_interface for the
|
||||||
|
// linux trusted OS simulator port of OPK. It uses the
|
||||||
|
// posix_services.h implementation of semaphores and shared memory
|
||||||
|
// which is based on the POSIX shared memory and semaphore libraries.
|
||||||
|
|
||||||
|
#include "odk_message.h"
|
||||||
|
#include "posix_resources.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* See "tos_transport_interface.h" for documentation of each of the
|
||||||
|
* TOS_ interface functions below.
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
using namespace posix;
|
||||||
|
|
||||||
|
// message request/response payload data
|
||||||
|
static RequestResponseBlock* shared_memory_ = nullptr;
|
||||||
|
|
||||||
|
// mailbox containing the size of the payload
|
||||||
|
static MailboxBlock* mailbox_memory_ = nullptr;
|
||||||
|
|
||||||
|
// post when a request message is ready
|
||||||
|
static RequestSemaphore* request_semaphore_ = nullptr;
|
||||||
|
|
||||||
|
// post when a response message is ready
|
||||||
|
static ResponseSemaphore* response_semaphore_ = nullptr;
|
||||||
|
|
||||||
|
static void ReleaseResources() {
|
||||||
|
if (shared_memory_) {
|
||||||
|
delete shared_memory_;
|
||||||
|
shared_memory_ = nullptr;
|
||||||
|
}
|
||||||
|
if (mailbox_memory_) {
|
||||||
|
delete mailbox_memory_;
|
||||||
|
mailbox_memory_ = nullptr;
|
||||||
|
}
|
||||||
|
if (request_semaphore_) {
|
||||||
|
delete request_semaphore_;
|
||||||
|
request_semaphore_ = nullptr;
|
||||||
|
}
|
||||||
|
if (response_semaphore_) {
|
||||||
|
delete response_semaphore_;
|
||||||
|
response_semaphore_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TOS_Transport_Initialize(void) {
|
||||||
|
if (!(shared_memory_ = new RequestResponseBlock()) ||
|
||||||
|
!(shared_memory_->Allocate(OPK_TRANSPORT_MESSAGE_SIZE))) {
|
||||||
|
ReleaseResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(mailbox_memory_ = new MailboxBlock()) ||
|
||||||
|
!(mailbox_memory_->Allocate(sizeof(uint32_t)))) {
|
||||||
|
ReleaseResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(request_semaphore_ = new RequestSemaphore())) {
|
||||||
|
ReleaseResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(response_semaphore_ = new ResponseSemaphore())) {
|
||||||
|
ReleaseResources();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TOS_Transport_Terminate(void) { ReleaseResources(); }
|
||||||
|
|
||||||
|
ODK_Message TOS_Transport_GetRequest() {
|
||||||
|
if (!shared_memory_) {
|
||||||
|
return ODK_Message_Create(nullptr, 0);
|
||||||
|
} else {
|
||||||
|
return ODK_Message_Create(shared_memory_->GetAddress(),
|
||||||
|
shared_memory_->GetSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ODK_Message TOS_Transport_GetResponse() {
|
||||||
|
/* Use the same shared memory block for request & response */
|
||||||
|
return TOS_Transport_GetRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TOS_Transport_ReleaseMessage(ODK_Message* message) {
|
||||||
|
// resources are static, nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// be in the shared memory by then, so return a response message
|
||||||
|
// constructed from the shared memory with the size in the mailbox.
|
||||||
|
|
||||||
|
OPK_TransportStatus TOS_Transport_SendMessage(ODK_Message* request,
|
||||||
|
ODK_Message* response) {
|
||||||
|
PokeSize(static_cast<uint32_t>(ODK_Message_GetSize(request)));
|
||||||
|
request_semaphore_->post();
|
||||||
|
response_semaphore_->wait();
|
||||||
|
*response = ODK_Message_Create(shared_memory_->GetAddress(),
|
||||||
|
shared_memory_->GetSize());
|
||||||
|
ODK_Message_SetSize(response, PeekSize());
|
||||||
|
return OPK_TRANSPORT_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* These are TOS functions only used by the tee_simulator, they are
|
||||||
|
* not an implementation of functions in the TOS transport interface.
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
// Wait for the request until signaled. Then the request payload will
|
||||||
|
// be in the shared memory and the size in the mailbox. Create a
|
||||||
|
// request message from the payload data and return it.
|
||||||
|
|
||||||
|
OPK_TransportStatus TOS_Transport_ReceiveRequest(ODK_Message* request) {
|
||||||
|
request_semaphore_->wait();
|
||||||
|
*request = ODK_Message_Create(shared_memory_->GetAddress(),
|
||||||
|
shared_memory_->GetSize());
|
||||||
|
ODK_Message_SetSize(request, PeekSize());
|
||||||
|
return OPK_TRANSPORT_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The response has been packed into the shared memory. Put the message
|
||||||
|
// size in the mailbox then post on the response semaphore to send it.
|
||||||
|
|
||||||
|
OPK_TransportStatus TOS_Transport_SendResponse(ODK_Message* response) {
|
||||||
|
PokeSize(static_cast<uint32_t>(ODK_Message_GetSize(response)));
|
||||||
|
response_semaphore_->post();
|
||||||
|
return OPK_TRANSPORT_STATUS_OK;
|
||||||
|
}
|
||||||
26
oemcrypto/opk/ports/linux/common/tos_transport.h
Normal file
26
oemcrypto/opk/ports/linux/common/tos_transport.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
|
||||||
|
#ifndef TOS_TRANSPORT_H_
|
||||||
|
#define TOS_TRANSPORT_H_
|
||||||
|
|
||||||
|
#include "odk_message.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* These functions are defined in the serialization adapter's
|
||||||
|
* tos_transport.c and tos_shared_memory.c to allow the tee simulator
|
||||||
|
* to use the transport and shared memory implementations. They are
|
||||||
|
* not part of the OPK OS interfaces.
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
// Request is in the shared memory, create a response from the shared
|
||||||
|
// buffer and post on the response semaphore.
|
||||||
|
OPK_TransportStatus TOS_Transport_ReceiveRequest(ODK_Message* request);
|
||||||
|
|
||||||
|
// Response is in the shared memory, post on the response
|
||||||
|
// semaphore to signal to the REE that it's ready.
|
||||||
|
OPK_TransportStatus TOS_Transport_SendResponse(ODK_Message* response);
|
||||||
|
|
||||||
|
#endif // TOS_TRANSPORT_H_
|
||||||
39
oemcrypto/opk/ports/linux/host/liboemcrypto/Makefile
Normal file
39
oemcrypto/opk/ports/linux/host/liboemcrypto/Makefile
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project).so
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.cpp \
|
||||||
|
$(liboemcrypto_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/oemcrypto_ta/include \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/liboemcrypto \
|
||||||
|
$(liboemcrypto_includes) \
|
||||||
|
|
||||||
|
cflags += \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"oemcrypto_ta\" \
|
||||||
|
|
||||||
|
ldflags = -lpthread -shared -lrt
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
|
|
||||||
17
oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp
Normal file
17
oemcrypto/opk/ports/linux/host/liboemcrypto/load_library.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine
|
||||||
|
// License Agreement.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "opk_init.h"
|
||||||
|
|
||||||
|
// When liboemcrypto is loaded, initialize the OPK
|
||||||
|
|
||||||
|
static void __attribute__((constructor)) Initialize_On_Load(void) {
|
||||||
|
OPK_Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((destructor)) Terminate_On_Close(void) {
|
||||||
|
OPK_Terminate();
|
||||||
|
}
|
||||||
31
oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/Makefile
Normal file
31
oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/Makefile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/include \
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -ldl -L$(builddir)/../liboemcrypto/ -loemcrypto \
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
|
|
||||||
|
|
||||||
20
oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c
Normal file
20
oemcrypto/opk/ports/linux/host/oemcrypto_helloworld/main.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Hello world\n");
|
||||||
|
|
||||||
|
OEMCryptoResult res;
|
||||||
|
res = OEMCrypto_Initialize();
|
||||||
|
printf("OEMCrypto_Initialize() returned %d", res);
|
||||||
|
|
||||||
|
OEMCrypto_Terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
oemcrypto/opk/ports/linux/host/oemcrypto_unittests/Makefile
Normal file
38
oemcrypto/opk/ports/linux/host/oemcrypto_unittests/Makefile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
# - TEEC_EXPORT: absolute path to libteec.so
|
||||||
|
# - PLATFORM: optee platform name, eg vexpress-qemu_virt
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(oemcrypto_unittests_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(oemcrypto_unittests_includes) \
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lpthread \
|
||||||
|
-lrt \
|
||||||
|
-L$(builddir)/../liboemcrypto/ -loemcrypto \
|
||||||
|
-static-libstdc++ \
|
||||||
|
|
||||||
|
cppflags += \
|
||||||
|
-DOPENSSL_NO_ASM \
|
||||||
|
-Wnon-virtual-dtor \
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
51
oemcrypto/opk/ports/linux/host/wtpi_unittests/Makefile
Normal file
51
oemcrypto/opk/ports/linux/host/wtpi_unittests/Makefile
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file expects the following definitions
|
||||||
|
# - CDM_DIR: absolute path to top of CDM repo.
|
||||||
|
# - PLATFORM: optee platform name, eg vexpress-qemu_virt
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# All file locations are relative to the $CDM_DIR path.
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
include $(srcdir)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_main.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_transport.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_secure_buffers.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_logging.c \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common/tos_shared_memory.c \
|
||||||
|
$(wtpi_unittests_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/wtpi_test_ta/include \
|
||||||
|
$(wtpi_unittests_includes) \
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lpthread \
|
||||||
|
-lrt \
|
||||||
|
-static-libstdc++ \
|
||||||
|
|
||||||
|
cppflags += \
|
||||||
|
-DOPENSSL_NO_ASM \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"wtpi_test_ta\" \
|
||||||
|
-Wnon-virtual-dtor \
|
||||||
|
-DCOSE_C_USE_OPENSSL \
|
||||||
|
-include 'cstdlib' \
|
||||||
|
'-DEVP_aes_128_ccm()=EVP_aes_128_gcm()' \
|
||||||
|
'-DEVP_aes_256_ccm()=EVP_aes_256_gcm()' \
|
||||||
|
'-DEVP_aes_192_ccm()=EVP_aes_192_gcm()' \
|
||||||
|
'-DEVP_CTRL_CCM_SET_L=0x14' \
|
||||||
|
'-DEVP_CTRL_CCM_GET_TAG=EVP_CTRL_GCM_GET_TAG' \
|
||||||
|
'-DEVP_CTRL_CCM_SET_TAG=EVP_CTRL_GCM_SET_TAG' \
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
31
oemcrypto/opk/ports/linux/liboemcrypto.gyp
Normal file
31
oemcrypto/opk/ports/linux/liboemcrypto.gyp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
'serialization_adapter_dir' : 'common',
|
||||||
|
},
|
||||||
|
'includes' : [
|
||||||
|
'../../serialization/settings.gypi',
|
||||||
|
],
|
||||||
|
'targets' : [
|
||||||
|
{
|
||||||
|
'toolsets' : [ 'target' ],
|
||||||
|
'target_name': 'liboemcrypto',
|
||||||
|
'type': 'shared_library',
|
||||||
|
'sources': [
|
||||||
|
'host/liboemcrypto/load_library.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_logging.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_secure_buffers.c',
|
||||||
|
'<(serialization_adapter_dir)/tos_shared_memory.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_transport.cpp',
|
||||||
|
],
|
||||||
|
'link_settings': {
|
||||||
|
'libraries': [
|
||||||
|
'-lpthread',
|
||||||
|
'-lrt'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'dependencies': [
|
||||||
|
'<(ree_dir)/ree.gyp:opk_ree',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
74
oemcrypto/opk/ports/linux/oemcrypto_tee_simulator.gyp
Normal file
74
oemcrypto/opk/ports/linux/oemcrypto_tee_simulator.gyp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
# Override the variables below for the location of various gyp files.
|
||||||
|
'privacy_crypto_impl%': 'boringssl',
|
||||||
|
'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
|
||||||
|
'boringssl_libssl_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:ssl',
|
||||||
|
'gtest_dependency%': '<(DEPTH)/third_party/googletest.gyp:gtest',
|
||||||
|
'gmock_dependency%': '<(DEPTH)/third_party/googletest.gyp:gmock',
|
||||||
|
'oemcrypto_dir%': '<(DEPTH)/oemcrypto',
|
||||||
|
'util_dir%': '<(DEPTH)/util',
|
||||||
|
'platform_specific_dir%': '<(DEPTH)/linux/src',
|
||||||
|
'serialization_adapter_dir' : 'common',
|
||||||
|
},
|
||||||
|
'includes' : {
|
||||||
|
'../../serialization/settings.gypi',
|
||||||
|
},
|
||||||
|
'target_defaults': {
|
||||||
|
'include_dirs' : [
|
||||||
|
'.',
|
||||||
|
'<(serialization_adapter_dir)',
|
||||||
|
'<(serialization_dir)/tee/include',
|
||||||
|
'<(util_dir)/include',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets' : [
|
||||||
|
{
|
||||||
|
'target_name': 'tee_simulator_oec_ref',
|
||||||
|
'type': 'executable',
|
||||||
|
'sources': [
|
||||||
|
'ta/common/clock.cpp',
|
||||||
|
'ta/common/tee_simulator.cpp',
|
||||||
|
'<(platform_specific_dir)/file_store.cpp',
|
||||||
|
'<(platform_specific_dir)/log.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_logging.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_secure_buffers.c',
|
||||||
|
'<(serialization_adapter_dir)/tos_shared_memory.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_transport.cpp',
|
||||||
|
'<(util_dir)/src/platform.cpp',
|
||||||
|
'<(util_dir)/src/rw_lock.cpp',
|
||||||
|
'<(util_dir)/src/string_conversions.cpp',
|
||||||
|
'<(util_dir)/src/string_format.cpp',
|
||||||
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'<(serialization_dir)/tee/tee.gyp:opk_tee',
|
||||||
|
'../../../testbed/oec_testbed.gyp:oec_testbed',
|
||||||
|
'../../../testbed/oec_testbed.gyp:utils_props_and_logs',
|
||||||
|
],
|
||||||
|
'libraries': ['-lrt', '-lpthread', '-ldl'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'tee_simulator_ta',
|
||||||
|
'type': 'executable',
|
||||||
|
'sources': [
|
||||||
|
'ta/common/clock.cpp',
|
||||||
|
'ta/common/tee_simulator.cpp',
|
||||||
|
'<(platform_specific_dir)/file_store.cpp',
|
||||||
|
'<(platform_specific_dir)/log.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_logging.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_secure_buffers.c',
|
||||||
|
'<(serialization_adapter_dir)/tos_shared_memory.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_transport.cpp',
|
||||||
|
'<(util_dir)/src/platform.cpp',
|
||||||
|
'<(util_dir)/src/rw_lock.cpp',
|
||||||
|
'<(util_dir)/src/string_conversions.cpp',
|
||||||
|
'<(util_dir)/src/string_format.cpp',
|
||||||
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'<(serialization_dir)/tee/tee.gyp:opk_tee',
|
||||||
|
'<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc',
|
||||||
|
],
|
||||||
|
'libraries': ['-lrt', '-lpthread', '-ldl'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
84
oemcrypto/opk/ports/linux/rules.mk
Normal file
84
oemcrypto/opk/ports/linux/rules.mk
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This makefile is a simple set of rules for compiling Linux example REE/TEE.
|
||||||
|
#
|
||||||
|
# Inputs:
|
||||||
|
# - srcdir: Relative path from parent Makefile to source file directory, eg top
|
||||||
|
# of repo.
|
||||||
|
# - builddir: Relative path from parent Makefile to destination directory.
|
||||||
|
# - srcs: List of source .c/.cpp/.cc/.S files. All entries in $(srcs)
|
||||||
|
# must be relative to $(srcdir)
|
||||||
|
# - incs: List of include paths. Must be relative to $(srcdir).
|
||||||
|
# - CROSS_COMPILE: prefix for gcc, eg arm-none-gnueabihf-
|
||||||
|
#
|
||||||
|
# Can optionally provide additional ldflags, cflags, cppflags, and global-incs
|
||||||
|
|
||||||
|
ifneq ($V,1)
|
||||||
|
q := @
|
||||||
|
cmd-echo := true
|
||||||
|
cmd-echo-silent := echo
|
||||||
|
else
|
||||||
|
q :=
|
||||||
|
cmd-echo := echo
|
||||||
|
cmd-echo-silent := true
|
||||||
|
endif
|
||||||
|
|
||||||
|
cc := $(CROSS_COMPILE)gcc
|
||||||
|
cxx := $(CROSS_COMPILE)g++
|
||||||
|
|
||||||
|
ssrc := $(patsubst %.S, %.o, $(filter %.S, $(srcs)))
|
||||||
|
csrc := $(patsubst %.c, %.o, $(filter %.c, $(srcs)))
|
||||||
|
cppsrc := $(patsubst %.cpp, %.o, $(filter %.cpp, $(srcs)))
|
||||||
|
ccsrc := $(patsubst %.cc, %.o, $(filter %.cc, $(srcs)))
|
||||||
|
objs = $(sort $(addprefix $(builddir), $(csrc) $(cppsrc) $(ccsrc) $(ssrc)))
|
||||||
|
|
||||||
|
includes += $(addprefix -I, $(addprefix $(srcdir)/, $(incs)) $(global-incs))
|
||||||
|
|
||||||
|
cflags += -Wall \
|
||||||
|
-Werror \
|
||||||
|
-fPIC \
|
||||||
|
$(includes) \
|
||||||
|
|
||||||
|
cflags_c += $(cflags) \
|
||||||
|
-std=c11 \
|
||||||
|
-D_POSIX_C_SOURCE=200809L \
|
||||||
|
-fno-inline
|
||||||
|
|
||||||
|
cppflags += $(cflags) \
|
||||||
|
$(CPPFLAGS) \
|
||||||
|
|
||||||
|
all: $(builddir)$(output)
|
||||||
|
|
||||||
|
$(builddir)$(output): $(objs)
|
||||||
|
@$(cmd-echo-silent) ' LD $@'
|
||||||
|
${q}$(cxx) -o $@ $(objs) $(ldadd) $(ldflags)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@$(cmd-echo-silent) ' CLEAN $(builddir)'
|
||||||
|
${q}rm -f $(objs) $(output)
|
||||||
|
@if [ -d $(builddir) ]; then rm -r $(builddir); fi
|
||||||
|
|
||||||
|
$(builddir)%.o: $(srcdir)%.c
|
||||||
|
${q}mkdir -p $(shell dirname $@)
|
||||||
|
@$(cmd-echo-silent) ' CC $@'
|
||||||
|
${q}$(cc) $(cflags_c) -c $< -o $@
|
||||||
|
|
||||||
|
$(builddir)%.o: $(srcdir)%.cc
|
||||||
|
${q}mkdir -p $(shell dirname $@)
|
||||||
|
@$(cmd-echo-silent) ' CPP $@'
|
||||||
|
${q}$(cxx) $(cppflags) -c $< -o $@
|
||||||
|
|
||||||
|
$(builddir)%.o: $(srcdir)%.cpp
|
||||||
|
${q}mkdir -p $(shell dirname $@)
|
||||||
|
@$(cmd-echo-silent) ' CPP $@'
|
||||||
|
${q}$(cxx) $(cppflags) -c $< -o $@
|
||||||
|
|
||||||
|
$(builddir)%.o: $(srcdir)%.S
|
||||||
|
${q}mkdir -p $(shell dirname $@)
|
||||||
|
@$(cmd-echo-silent) ' CC $@'
|
||||||
|
${q}$(cc) $(cflags_c) -c $< -o $@
|
||||||
20
oemcrypto/opk/ports/linux/scripts/build.sh
Executable file
20
oemcrypto/opk/ports/linux/scripts/build.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Builds OEMCrypto unit tests and WTPI unit tests, along with TEE simulators for
|
||||||
|
# each.
|
||||||
|
|
||||||
|
if [ -z "$CDM_DIR" ]; then
|
||||||
|
echo "CDM_DIR must be set to the top of the repo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
build_linux() {
|
||||||
|
pushd $CDM_DIR
|
||||||
|
make -j$(nproc) -C ./oemcrypto/opk/ports/linux all $1
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
# See Makefiles in oemcrypto_ta and wtpi_test_ta for how the PROVISIONING_METHOD
|
||||||
|
# var is used
|
||||||
|
build_linux PROVISIONING_METHOD=OEMCrypto_Keybox
|
||||||
|
|
||||||
|
# build_linux PROVISIONING_METHOD=OEMCrypto_BootCertificateChain
|
||||||
57
oemcrypto/opk/ports/linux/scripts/run.sh
Executable file
57
oemcrypto/opk/ports/linux/scripts/run.sh
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Runs OEMCrypto unit tests and WTPI unit tests, assuming they were built using
|
||||||
|
# the Makefile provided.
|
||||||
|
# Race conditions sometimes occur, causing the executables to hang at the
|
||||||
|
# beginning of each test suite, so don't rely on these for CI/CD or production.
|
||||||
|
|
||||||
|
if [ -z "$CDM_DIR" ]; then
|
||||||
|
echo "CDM_DIR must be set to the top of the repo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
kill_ta_simulators() {
|
||||||
|
oemcrypto_ta_pid=$(ps aux | grep '[o]emcrypto_ta' | awk '{print $2}')
|
||||||
|
wtpi_ta_pid=$(ps aux | grep '[w]tpi_test_ta' | awk '{print $2}')
|
||||||
|
|
||||||
|
if [ -n "$oemcrypto_ta_pid" ]; then
|
||||||
|
echo "Terminating OEMCrypto TA simulator (PID $oemcrypto_ta_pid)"
|
||||||
|
kill $oemcrypto_ta_pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$wtpi_ta_pid" ]; then
|
||||||
|
echo "Terminating WTPI Test TA simulator (PID $wtpi_ta_pid)"
|
||||||
|
kill $wtpi_ta_pid
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tests() {
|
||||||
|
builddir=$CDM_DIR/out/linux
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$builddir/liboemcrypto
|
||||||
|
|
||||||
|
$builddir/oemcrypto_ta/oemcrypto_ta &
|
||||||
|
$builddir/wtpi_test_ta/wtpi_test_ta &
|
||||||
|
|
||||||
|
trap kill_ta_simulators EXIT
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
wtpi_ta_pid=$(ps aux | grep '[w]tpi_test_ta' | awk '{print $2}')
|
||||||
|
if [[ -f "/proc/$wtpi_ta_pid/stat" ]]; then
|
||||||
|
$builddir/wtpi_unittests/wtpi_unittests --gtest_filter="-*Reboot*"
|
||||||
|
else
|
||||||
|
echo "WTPI TA simulator did not start."
|
||||||
|
FINAL_RESULT=43
|
||||||
|
fi
|
||||||
|
|
||||||
|
oemcrypto_ta_pid=$(ps aux | grep '[o]emcrypto_ta' | awk '{print $2}')
|
||||||
|
if [[ -f "/proc/$oemcrypto_ta_pid/stat" ]]; then
|
||||||
|
$builddir/oemcrypto_unittests/oemcrypto_unittests
|
||||||
|
else
|
||||||
|
echo "OEMCrypto TA simulator did not start."
|
||||||
|
FINAL_RESULT=43
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tests
|
||||||
|
|
||||||
|
exit $FINAL_RESULT
|
||||||
20
oemcrypto/opk/ports/linux/ta/common/clock.cpp
Normal file
20
oemcrypto/opk/ports/linux/ta/common/clock.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
//
|
||||||
|
// Clock - implemented using the standard linux time library
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
namespace wvutil {
|
||||||
|
|
||||||
|
int64_t Clock::GetCurrentTime() {
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = tv.tv_usec = 0;
|
||||||
|
gettimeofday(&tv, nullptr);
|
||||||
|
return tv.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wvutil
|
||||||
104
oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp
Normal file
104
oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "odk_message.h"
|
||||||
|
#include "opk_dispatcher.h"
|
||||||
|
#include "opk_init.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "tos_transport.h"
|
||||||
|
#include "tos_transport_interface.h"
|
||||||
|
|
||||||
|
static pthread_t main_thread_tid;
|
||||||
|
static bool thread_running = false;
|
||||||
|
|
||||||
|
void signalHandler(int signum) {
|
||||||
|
// TODO(fredgc): this doesn't actually kill anything because the main loop is
|
||||||
|
// stuck waiting for a new message.
|
||||||
|
thread_running = false;
|
||||||
|
// This exits, but then we skip the OPK_Terminate call.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request message data must be copied into a local buffer
|
||||||
|
// so the contents can't be modified while being parsed.
|
||||||
|
static uint8_t local_buffer[OPK_TRANSPORT_MESSAGE_SIZE];
|
||||||
|
|
||||||
|
static void* MainLoop(void* arg) {
|
||||||
|
OPK_Initialize();
|
||||||
|
thread_running = true;
|
||||||
|
while (thread_running) {
|
||||||
|
ODK_Message request, response;
|
||||||
|
OPK_TransportStatus transport_status =
|
||||||
|
TOS_Transport_ReceiveRequest(&request);
|
||||||
|
if (transport_status != OPK_TRANSPORT_STATUS_OK) {
|
||||||
|
LOGE("Receive request failed: status=%s",
|
||||||
|
OPK_TransportStatus_Str(transport_status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// !! IMPORTANT NOTE !!
|
||||||
|
// The request payload buffer MUST be copied out to TEE local
|
||||||
|
// storage so it can't be tampered with while being
|
||||||
|
// parsed. Failure to do so could introduce security
|
||||||
|
// vulnerabilities.
|
||||||
|
//
|
||||||
|
size_t payload_size = ODK_Message_GetSize(&request);
|
||||||
|
memcpy(local_buffer, ODK_Message_GetBase(&request), payload_size);
|
||||||
|
ODK_Message safe_request =
|
||||||
|
ODK_Message_Create(local_buffer, sizeof(local_buffer));
|
||||||
|
ODK_Message_SetSize(&safe_request, payload_size);
|
||||||
|
|
||||||
|
ODK_MessageStatus message_status =
|
||||||
|
OPK_DispatchMessage(&safe_request, &response);
|
||||||
|
if (message_status != MESSAGE_STATUS_OK) {
|
||||||
|
LOGE("Dispatch failed: status=%s", OPK_MessageStatus_Str(message_status));
|
||||||
|
}
|
||||||
|
transport_status = TOS_Transport_SendResponse(&response);
|
||||||
|
if (transport_status != OPK_TRANSPORT_STATUS_OK) {
|
||||||
|
LOGE("Send response failed: status=%s",
|
||||||
|
OPK_TransportStatus_Str(transport_status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TOS_Transport_ReleaseMessage(&request);
|
||||||
|
TOS_Transport_ReleaseMessage(&response);
|
||||||
|
}
|
||||||
|
OPK_Terminate();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
pthread_attr_t p_attr;
|
||||||
|
|
||||||
|
int result = pthread_attr_init(&p_attr);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed pthread_attr_init: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("Reset shared resource state");
|
||||||
|
system("rm /dev/shm/*opk*");
|
||||||
|
|
||||||
|
LOGI("Starting the main loop thread");
|
||||||
|
result = pthread_create(&main_thread_tid, &p_attr, &MainLoop, nullptr);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed to spawn a thread: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
signal(SIGTERM, signalHandler);
|
||||||
|
LOGI("Main is waiting for the main loop thread to exit");
|
||||||
|
void* retval;
|
||||||
|
result = pthread_join(main_thread_tid, &retval);
|
||||||
|
if (result != 0) {
|
||||||
|
LOGF("Failed to join main thread: %s", strerror(errno));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine License
|
||||||
|
Agreement. */
|
||||||
|
|
||||||
|
#include "layer2_crypto_key_table.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "wtpi_abort_interface.h"
|
||||||
|
#include "wtpi_config_macros.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This is a test implementation of the simulation of the crypto key table which
|
||||||
|
* is supported by hardware. A doubly linked list and a FIFO eviction algorithm
|
||||||
|
* is implemented. When a key gets evicted, a callback is triggered to notify
|
||||||
|
* the key holder in the upper layer, presumably, crypto and key management
|
||||||
|
* layer 2.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A minimum number of 4 key slots is required in order to successfully open a
|
||||||
|
* session and load the encryption and mac keys.
|
||||||
|
*/
|
||||||
|
#if MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES < 4
|
||||||
|
# error "MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES must be at least 4"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INDEX_OUT_OF_BOUND MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES
|
||||||
|
|
||||||
|
typedef struct k2_symmetric_key {
|
||||||
|
SymmetricKeyType key_type;
|
||||||
|
uint8_t aes_key[MAX_SYMMETRIC_KEY_SIZE];
|
||||||
|
KeySize size;
|
||||||
|
} K2_SymmetricKey;
|
||||||
|
|
||||||
|
typedef struct k2_key_table_entry {
|
||||||
|
K2_SymmetricKey key;
|
||||||
|
bool is_used;
|
||||||
|
uint32_t prev;
|
||||||
|
uint32_t next;
|
||||||
|
} K2_KeyTableEntry;
|
||||||
|
|
||||||
|
typedef struct k2_key_table {
|
||||||
|
K2_KeyTableEntry entries[MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES];
|
||||||
|
uint32_t first_free, last_free;
|
||||||
|
uint32_t first_used, last_used;
|
||||||
|
OEMCryptoResult (*eviction_callback)(uint32_t);
|
||||||
|
} K2_KeyTable;
|
||||||
|
|
||||||
|
static K2_KeyTable gKeyTable;
|
||||||
|
|
||||||
|
/** Move key |index| from the free queue to the used queue. */
|
||||||
|
static void MoveToUsed(K2_KeyTable* table, uint32_t index) {
|
||||||
|
if (!table || !K2_IsIndexValid(index)) return;
|
||||||
|
if (table->entries[index].is_used) return;
|
||||||
|
|
||||||
|
// remove from free queue and update first_free or last_free as needed
|
||||||
|
if (table->entries[index].prev != INDEX_OUT_OF_BOUND) {
|
||||||
|
table->entries[table->entries[index].prev].next =
|
||||||
|
table->entries[index].next;
|
||||||
|
}
|
||||||
|
if (table->entries[index].next != INDEX_OUT_OF_BOUND) {
|
||||||
|
table->entries[table->entries[index].next].prev =
|
||||||
|
table->entries[index].prev;
|
||||||
|
}
|
||||||
|
if (index == table->first_free) {
|
||||||
|
table->first_free = table->entries[table->first_free].next;
|
||||||
|
}
|
||||||
|
if (index == table->last_free) {
|
||||||
|
table->last_free = table->entries[table->last_free].prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to the tail of used queue
|
||||||
|
if (table->last_used == INDEX_OUT_OF_BOUND) {
|
||||||
|
table->first_used = index;
|
||||||
|
table->entries[index].prev = INDEX_OUT_OF_BOUND;
|
||||||
|
} else {
|
||||||
|
table->entries[table->last_used].next = index;
|
||||||
|
table->entries[index].prev = table->last_used;
|
||||||
|
}
|
||||||
|
table->entries[index].is_used = true;
|
||||||
|
table->entries[index].next = INDEX_OUT_OF_BOUND;
|
||||||
|
table->last_used = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Move key |index| from the used queue to the free queue. */
|
||||||
|
static void MoveToFree(K2_KeyTable* table, uint32_t index) {
|
||||||
|
if (!table || !K2_IsIndexValid(index)) return;
|
||||||
|
if (!table->entries[index].is_used) return;
|
||||||
|
|
||||||
|
memset(&table->entries[index].key, 0, sizeof(table->entries[index].key));
|
||||||
|
|
||||||
|
// remove from used queue and update first_used or last_used as needed
|
||||||
|
if (table->entries[index].prev != INDEX_OUT_OF_BOUND) {
|
||||||
|
table->entries[table->entries[index].prev].next =
|
||||||
|
table->entries[index].next;
|
||||||
|
}
|
||||||
|
if (table->entries[index].next != INDEX_OUT_OF_BOUND) {
|
||||||
|
table->entries[table->entries[index].next].prev =
|
||||||
|
table->entries[index].prev;
|
||||||
|
}
|
||||||
|
if (index == table->first_used) {
|
||||||
|
table->first_used = table->entries[table->first_used].next;
|
||||||
|
}
|
||||||
|
if (index == table->last_used) {
|
||||||
|
table->last_used = table->entries[table->last_used].prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to the tail of free queue
|
||||||
|
if (table->last_free == INDEX_OUT_OF_BOUND) {
|
||||||
|
table->first_free = index;
|
||||||
|
table->entries[index].prev = INDEX_OUT_OF_BOUND;
|
||||||
|
} else {
|
||||||
|
table->entries[table->last_free].next = index;
|
||||||
|
table->entries[index].prev = table->last_free;
|
||||||
|
}
|
||||||
|
table->entries[index].is_used = false;
|
||||||
|
table->entries[index].next = INDEX_OUT_OF_BOUND;
|
||||||
|
table->last_free = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OEMCryptoResult GetNextAvailable(K2_KeyTable* table, uint32_t* index) {
|
||||||
|
if (table == NULL || index == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
*index = INDEX_OUT_OF_BOUND;
|
||||||
|
if (table->first_free < INDEX_OUT_OF_BOUND) {
|
||||||
|
*index = table->first_free;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
// eviction: key and handle removal is done in callback
|
||||||
|
uint32_t eviction = table->first_used;
|
||||||
|
if (!K2_IsIndexValid(eviction)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
OEMCryptoResult result = table->eviction_callback(eviction);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
MoveToFree(table, eviction);
|
||||||
|
*index = eviction;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult K2_InitializeKeyTable(void) {
|
||||||
|
for (uint32_t i = 0; i < MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES; ++i) {
|
||||||
|
memset(&gKeyTable.entries[i].key, 0, sizeof(gKeyTable.entries[i].key));
|
||||||
|
gKeyTable.entries[i].next = i + 1;
|
||||||
|
if (i == 0) {
|
||||||
|
gKeyTable.entries[i].prev = INDEX_OUT_OF_BOUND;
|
||||||
|
} else {
|
||||||
|
gKeyTable.entries[i].prev = i - 1;
|
||||||
|
}
|
||||||
|
gKeyTable.entries[i].is_used = false;
|
||||||
|
}
|
||||||
|
gKeyTable.first_free = 0;
|
||||||
|
gKeyTable.last_free = INDEX_OUT_OF_BOUND - 1;
|
||||||
|
gKeyTable.first_used = INDEX_OUT_OF_BOUND;
|
||||||
|
gKeyTable.last_used = INDEX_OUT_OF_BOUND;
|
||||||
|
gKeyTable.eviction_callback = NULL;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool K2_IsIndexValid(uint32_t index) { return index < INDEX_OUT_OF_BOUND; }
|
||||||
|
|
||||||
|
bool K2_IsKeyValid(uint32_t index) {
|
||||||
|
if (!K2_IsIndexValid(index)) return false;
|
||||||
|
if (!gKeyTable.entries[index].is_used) return false;
|
||||||
|
K2_SymmetricKey* key = &gKeyTable.entries[index].key;
|
||||||
|
switch (key->key_type) {
|
||||||
|
case CONTENT_KEY:
|
||||||
|
// We cheat a little here. We also call generic crypto keys "content
|
||||||
|
// keys", even though some of them are 256 bit HMAC keys.
|
||||||
|
return key->size == KEY_SIZE_128 || key->size == KEY_SIZE_256;
|
||||||
|
case ENTITLEMENT_KEY:
|
||||||
|
case MAC_KEY_SERVER:
|
||||||
|
case MAC_KEY_CLIENT:
|
||||||
|
return key->size == KEY_SIZE_256;
|
||||||
|
case ENCRYPTION_KEY:
|
||||||
|
case DERIVING_KEY:
|
||||||
|
return key->size == KEY_SIZE_128;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void K2_SetEvictionCallback(OEMCryptoResult (*callback)(uint32_t)) {
|
||||||
|
gKeyTable.eviction_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* K2_GetKey(uint32_t index) {
|
||||||
|
ABORT_IF(!K2_IsKeyValid(index), "Invalid key.");
|
||||||
|
return gKeyTable.entries[index].key.aes_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySize K2_GetKeySize(uint32_t index) {
|
||||||
|
ABORT_IF(!K2_IsKeyValid(index), "Invalid key.");
|
||||||
|
return gKeyTable.entries[index].key.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymmetricKeyType K2_GetKeyType(uint32_t index) {
|
||||||
|
ABORT_IF(!K2_IsKeyValid(index), "Invalid key.");
|
||||||
|
return gKeyTable.entries[index].key.key_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult K2_AddKey(const uint8_t* key_bytes, size_t size,
|
||||||
|
SymmetricKeyType key_type, uint32_t* index) {
|
||||||
|
if (key_bytes == NULL || size == 0 || index == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint32_t next = INDEX_OUT_OF_BOUND;
|
||||||
|
OEMCryptoResult result = GetNextAvailable(&gKeyTable, &next);
|
||||||
|
if (result == OEMCrypto_SUCCESS) {
|
||||||
|
MoveToUsed(&gKeyTable, next);
|
||||||
|
gKeyTable.entries[next].key.size = (KeySize)size;
|
||||||
|
gKeyTable.entries[next].key.key_type = key_type;
|
||||||
|
memcpy(gKeyTable.entries[next].key.aes_key, key_bytes, size);
|
||||||
|
}
|
||||||
|
*index = next;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult K2_RemoveKey(uint32_t index) {
|
||||||
|
if (!K2_IsIndexValid(index) || !gKeyTable.entries[index].is_used) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
MoveToFree(&gKeyTable, index);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/* Copyright 2021 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_LAYER2_CRYPTO_KEY_TABLE_H_
|
||||||
|
#define OEMCRYPTO_TA_LAYER2_CRYPTO_KEY_TABLE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "OEMCryptoCENCCommon.h"
|
||||||
|
#include "oemcrypto_key_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This header file provides functions of the AES key table which simulates a
|
||||||
|
* hardware-backed key table with a limited number of key slots. They should be
|
||||||
|
* only called by the TEST implementation of Crypto and Key Management layer 2.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the layer 2 key table.
|
||||||
|
*/
|
||||||
|
OEMCryptoResult K2_InitializeKeyTable(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if |index| is a valid key slot in the key table. Returns true if it
|
||||||
|
* is. Otherwise returns false.
|
||||||
|
*/
|
||||||
|
bool K2_IsIndexValid(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the key in key slot |index| is valid. Returns true if it is.
|
||||||
|
* Otherwise returns false.
|
||||||
|
*/
|
||||||
|
bool K2_IsKeyValid(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds |size| bytes of |key_bytes| as a key entry to the key table, and sets
|
||||||
|
* |index| to the allocated key slot.
|
||||||
|
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, or
|
||||||
|
* if |size| is 0. Returns OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if the key
|
||||||
|
* table runs out of key slots and key eviction fails.
|
||||||
|
* Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
|
||||||
|
* OEMCrypto_SUCCESS otherwise.
|
||||||
|
* Caller retains ownership of all pointers.
|
||||||
|
*/
|
||||||
|
OEMCryptoResult K2_AddKey(const uint8_t* key_bytes, size_t size,
|
||||||
|
SymmetricKeyType key_type, uint32_t* index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes key in key slot |index|.
|
||||||
|
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if |index| is not valid, and
|
||||||
|
* OEMCrypto_SUCCESS otherwise.
|
||||||
|
*/
|
||||||
|
OEMCryptoResult K2_RemoveKey(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the AES key bytes from key slot |index|. |index| must be valid.
|
||||||
|
*/
|
||||||
|
uint8_t* K2_GetKey(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the AES key size from key slot |index|. |index| must be valid.
|
||||||
|
*/
|
||||||
|
KeySize K2_GetKeySize(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the AES key type from key slot |index|. |index| must be valid.
|
||||||
|
*/
|
||||||
|
SymmetricKeyType K2_GetKeyType(uint32_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the key eviction handler. The handler takes a key slot to be evicted and
|
||||||
|
* returns OEMCryptoResult.
|
||||||
|
*/
|
||||||
|
void K2_SetEvictionCallback(OEMCryptoResult (*callback)(uint32_t));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OEMCRYPTO_TA_LAYER2_CRYPTO_KEY_TABLE_H_ */
|
||||||
53
oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk
Normal file
53
oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file lists out the files that implement the WTPI and transport layer for
|
||||||
|
# the OPTEE port. This includes a few reference files from `wtpi_reference`, as
|
||||||
|
# well as stubs from `wtpi_useless` that must be replaced for a production
|
||||||
|
# build.
|
||||||
|
#
|
||||||
|
# This is not necessary for other ports. This only exists to consoldiate all of
|
||||||
|
# the OPTEE-specific code in one place for use in sub.mk
|
||||||
|
|
||||||
|
wtpi_impl_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl
|
||||||
|
wtpi_stub_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_useless
|
||||||
|
wtpi_ref_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/oemcrypto_ta/wtpi_reference
|
||||||
|
tos_impl_dir ?= $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common
|
||||||
|
|
||||||
|
wtpi_impl_sources += \
|
||||||
|
$(wtpi_impl_dir)/wtpi_oemcrypto_config.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_crypto_and_key_management_layer1_openssl.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_crypto_asymmetric.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_decrypt_sample.c \
|
||||||
|
$(wtpi_impl_dir)/wtpi_init_and_clock_ipc.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_abort.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_device_key.c \
|
||||||
|
$(wtpi_ref_dir)/crypto_util.c \
|
||||||
|
$(wtpi_ref_dir)/rsa_util.c \
|
||||||
|
$(wtpi_ref_dir)/ecc_util.c \
|
||||||
|
$(wtpi_ref_dir)/cose_util.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_logging.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_root_of_trust_layer1.c \
|
||||||
|
$(wtpi_ref_dir)/renewal_util.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_clock_and_gn_layer1.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_crc32.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_crypto_wrap_asymmetric.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_idle.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_device_renewal_layer1.c \
|
||||||
|
$(wtpi_ref_dir)/wtpi_device_renewal_layer2.c \
|
||||||
|
$(wtpi_stub_dir)/wtpi_device_key_access.c \
|
||||||
|
$(wtpi_stub_dir)/wtpi_persistent_storage.c \
|
||||||
|
$(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c \
|
||||||
|
$(wtpi_stub_dir)/wtpi_secure_buffer_access.c \
|
||||||
|
$(tos_impl_dir)/tos_secure_buffers.c \
|
||||||
|
$(tos_impl_dir)/tos_transport.cpp \
|
||||||
|
|
||||||
|
wtpi_impl_includes += \
|
||||||
|
$(wtpi_impl_dir) \
|
||||||
|
$(wtpi_ref_dir) \
|
||||||
|
$(wtpi_ref_dir)/../wtpi \
|
||||||
|
$(oemcrypto_dir)/include \
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine License
|
||||||
|
Agreement. */
|
||||||
|
|
||||||
|
#include "file_store_interface.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "wtpi_abort_interface.h"
|
||||||
|
#include "wtpi_logging_interface.h"
|
||||||
|
|
||||||
|
#define PATH_MAX 256
|
||||||
|
static const char kDirectoryDelimiter = '/';
|
||||||
|
|
||||||
|
typedef struct tee_file_handle {
|
||||||
|
FILE* file;
|
||||||
|
const char* path;
|
||||||
|
} tee_file_handle;
|
||||||
|
|
||||||
|
static bool IsFileHandleValid(File_Handle handle) {
|
||||||
|
return (handle != NULL && handle->file != NULL && PathExists(handle->path));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create all the subdirectories on |dir|, if they don't exist. |dir| can be
|
||||||
|
* either a relative or an absolute path to the storage file, not including the
|
||||||
|
* file name. */
|
||||||
|
static bool CreateDirectories(const char* dir) {
|
||||||
|
if (dir == NULL) return false;
|
||||||
|
char mutable_dir[PATH_MAX];
|
||||||
|
size_t len = strlen(dir);
|
||||||
|
if (len > sizeof(mutable_dir) - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(mutable_dir, dir, len);
|
||||||
|
mutable_dir[len] = '\0';
|
||||||
|
char* pos;
|
||||||
|
errno = 0;
|
||||||
|
for (pos = mutable_dir + 1; *pos; pos++) {
|
||||||
|
if (*pos == kDirectoryDelimiter) {
|
||||||
|
*pos = '\0';
|
||||||
|
if (mkdir(mutable_dir, S_IRWXU) != 0) {
|
||||||
|
if (errno != EEXIST) return false;
|
||||||
|
}
|
||||||
|
*pos = kDirectoryDelimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mkdir(mutable_dir, S_IRWXU) != 0) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PathExists(const char* path) {
|
||||||
|
struct stat buf;
|
||||||
|
return (stat(path, &buf) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
File_Handle FileOpen(const char* path, int flags) {
|
||||||
|
if (path == NULL) return NULL;
|
||||||
|
if (!PathExists(path)) {
|
||||||
|
/* Strip file name off and create all sub-directories. */
|
||||||
|
const char* last_delimiter = strrchr(path, kDirectoryDelimiter);
|
||||||
|
if (last_delimiter != NULL) {
|
||||||
|
char dir[PATH_MAX];
|
||||||
|
size_t len = last_delimiter - path;
|
||||||
|
if (len > sizeof(dir) - 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(dir, path, len);
|
||||||
|
dir[len] = '\0';
|
||||||
|
if (!PathExists(dir) && !CreateDirectories(dir)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FILE* fp;
|
||||||
|
if (((flags & FILE_OPEN_TRUNCATE) && PathExists(path)) ||
|
||||||
|
((flags & FILE_OPEN_CREATE) && !PathExists(path))) {
|
||||||
|
fp = fopen(path, "wb");
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* open_flags = (flags & FILE_OPEN_READ_ONLY) ? "rb" : "wb";
|
||||||
|
if ((fp = fopen(path, open_flags)) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
File_Handle handle = malloc(sizeof(tee_file_handle));
|
||||||
|
if (handle == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
handle->file = fp;
|
||||||
|
handle->path = path;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileRead(File_Handle handle, char* buffer, size_t bytes) {
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Handle is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ABORT_IF(!IsFileHandleValid(handle), "Impossible file handle.");
|
||||||
|
if (buffer == NULL) {
|
||||||
|
LOGE("Buffer is empty");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t len = fread(buffer, sizeof(char), bytes, handle->file);
|
||||||
|
if (len != bytes) {
|
||||||
|
if (ferror(handle->file)) {
|
||||||
|
LOGE("Error reading %zu bytes, error=%d", bytes, ferror(handle->file));
|
||||||
|
} else if (feof(handle->file)) {
|
||||||
|
LOGE("Error reading %zu bytes, unexpected EOF", bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (int)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileWrite(File_Handle handle, const char* buffer, size_t bytes) {
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Handle is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ABORT_IF(!IsFileHandleValid(handle), "Impossible file handle.");
|
||||||
|
if (buffer == NULL) {
|
||||||
|
LOGE("Buffer is empty");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t len = fwrite(buffer, sizeof(char), bytes, handle->file);
|
||||||
|
if (len != bytes) {
|
||||||
|
LOGE("Error writing %zu bytes, error=%d", bytes, ferror(handle->file));
|
||||||
|
}
|
||||||
|
fflush(handle->file);
|
||||||
|
return (int)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileSize(File_Handle handle) {
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Handle is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ABORT_IF(!IsFileHandleValid(handle), "Impossible file handle.");
|
||||||
|
struct stat buf;
|
||||||
|
if (stat(handle->path, &buf) == 0) {
|
||||||
|
return (int)buf.st_size;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileClose(File_Handle handle) {
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Handle is NULL");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ABORT_IF(!IsFileHandleValid(handle), "Impossible file handle.");
|
||||||
|
fclose(handle->file);
|
||||||
|
free(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright 2021 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_FILE_STORE_INTERFACE_H_
|
||||||
|
#define OEMCRYPTO_TA_FILE_STORE_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FILE_OPEN_NO_FLAG 0x0
|
||||||
|
#define FILE_OPEN_CREATE 0x1
|
||||||
|
#define FILE_OPEN_READ_ONLY 0x2
|
||||||
|
#define FILE_OPEN_TRUNCATE 0x4
|
||||||
|
|
||||||
|
typedef struct tee_file_handle* File_Handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a file or a directory exists.
|
||||||
|
*/
|
||||||
|
bool PathExists(const char* path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a file handle from |path| with open flags |flags|.
|
||||||
|
*/
|
||||||
|
File_Handle FileOpen(const char* path, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads |bytes| data to |buffer| from file handle |handle|. Returns the
|
||||||
|
* number of data read on success, -1 on failure. Caller retains ownership of
|
||||||
|
* all pointers, and ensures the size of |buffer| is at least as big as |bytes|.
|
||||||
|
*/
|
||||||
|
int FileRead(File_Handle handle, char* buffer, size_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes |bytes| data from |buffer| to file handle |handle|. Returns the
|
||||||
|
* number of data written on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
int FileWrite(File_Handle handle, const char* buffer, size_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of file on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
int FileSize(File_Handle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees |handle| that was constructed from a previous call to FileOpen.
|
||||||
|
*/
|
||||||
|
bool FileClose(File_Handle handle);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* OEMCRYPTO_TA_FILE_STORE_INTERFACE_H_ */
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/* 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 "wtpi_cas_interface.h"
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InitializeCas(void) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_TerminateCas(void) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_AllocateKeySlotDescriptor(OEMCrypto_SESSION session_id,
|
||||||
|
void** key_slot_descriptor) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_FreeKeySlotDescriptor(void* key_slot_descriptor) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentKey(void* key_slot_descriptor,
|
||||||
|
WTPI_K1_SymmetricKey_Handle key_handle,
|
||||||
|
OEMCryptoCipherMode cipher_mode,
|
||||||
|
bool is_even) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_InstallContentIV(void* key_slot_descriptor, uint8_t* iv,
|
||||||
|
size_t iv_length, bool is_even) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetKeyToken(void* key_slot_descriptor, uint8_t* key_token,
|
||||||
|
size_t* key_token_length) {
|
||||||
|
// TODO
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_GetKeyTokenSize(void) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_device_key_access_interface.h"
|
||||||
|
|
||||||
|
/* This implementation uses a hardcoded fake device key. Reboot tests requires
|
||||||
|
* a constant device key across reboots. Provisioning 4.0 tests against the
|
||||||
|
* reference implementation also requires a constant device key for deriving a
|
||||||
|
* Boot Certificate Chain which can be pre-registered by the provision server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint8_t fake_device_key[KEY_SIZE_128] = {
|
||||||
|
0xa2, 0xe5, 0x11, 0x54, 0x12, 0x60, 0xf0, 0xe1,
|
||||||
|
0xa8, 0x72, 0xeb, 0x15, 0x48, 0x41, 0xc7, 0x87};
|
||||||
|
|
||||||
|
const uint8_t* WTPI_GetDeviceKey(void) { return fake_device_key; }
|
||||||
|
|
||||||
|
KeySize WTPI_GetDeviceKeySize(void) {
|
||||||
|
return (KeySize)(sizeof(fake_device_key));
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_clock_interface_layer1.h"
|
||||||
|
#include "wtpi_clock_interface_layer2.h"
|
||||||
|
|
||||||
|
#include <clock.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "file_store_interface.h"
|
||||||
|
#include "oemcrypto_wall_clock.h"
|
||||||
|
#include "wtpi_initialize_terminate_interface.h"
|
||||||
|
#include "wtpi_logging_interface.h"
|
||||||
|
|
||||||
|
// These functions are used for the test implementation when
|
||||||
|
// we do NOT have an IPC to set the wall clock time.
|
||||||
|
|
||||||
|
// We simulate a secure timer by resting it to 0 on initalization.
|
||||||
|
static uint64_t gInitialTime = 0;
|
||||||
|
|
||||||
|
/* Test implementations of Initialize and Terminate functions. */
|
||||||
|
extern "C" OEMCryptoResult WTPI_Initialize(void) {
|
||||||
|
LOGD("WTPI_Initialize.");
|
||||||
|
gInitialTime = wvutil::Clock().GetCurrentTime();
|
||||||
|
// When running in a test environment without the IPC code, we need to
|
||||||
|
// initialize the wall clock to be the same as the fake clock. Otherwise, we
|
||||||
|
// ignore fake sleeps between Terminate and the next Initialize.
|
||||||
|
OPK_SetWallClockTime(gInitialTime);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" OEMCryptoResult WTPI_Terminate(void) {
|
||||||
|
LOGD("WTPI_Terminate.");
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" OEMCryptoResult WTPI_GetSecureTimer(uint64_t* time_in_s) {
|
||||||
|
if (!time_in_s) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
uint64_t now = wvutil::Clock().GetCurrentTime();
|
||||||
|
// Since there is no transport layer running, we must set the wall clock
|
||||||
|
// somewhere. This is as good a place as any.
|
||||||
|
OPK_SetWallClockTime(now);
|
||||||
|
// Pretend secure timer started at initialization time.
|
||||||
|
*time_in_s = now > gInitialTime ? now - gInitialTime : 0;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine License
|
||||||
|
Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_persistent_storage.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "file_store_interface.h"
|
||||||
|
#include "wtpi_logging_interface.h"
|
||||||
|
|
||||||
|
static const char* kPersistentDataPath = "./out/generation_number.dat";
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_PrepareStoredPersistentData(void) {
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length) {
|
||||||
|
LOGD("Requesting %zd bytes persistent data", *data_length);
|
||||||
|
if (!data || !data_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
if (!PathExists(kPersistentDataPath)) {
|
||||||
|
LOGD("WTPI_LoadPersistentData: no data");
|
||||||
|
return OPK_ERROR_NO_PERSISTENT_DATA;
|
||||||
|
}
|
||||||
|
File_Handle handle = FileOpen(kPersistentDataPath, FILE_OPEN_READ_ONLY);
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Failed to open file %s", kPersistentDataPath);
|
||||||
|
return OPK_ERROR_NO_PERSISTENT_DATA;
|
||||||
|
}
|
||||||
|
if ((int)*data_length < FileSize(handle)) {
|
||||||
|
LOGE("Too much persistent data: %d", FileSize(handle));
|
||||||
|
*data_length = FileSize(handle);
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
// If the file exists, we read the data we can, and return success.
|
||||||
|
// The calling procedure will deal with a short buffer.
|
||||||
|
*data_length = FileRead(handle, (char*)(data), *data_length);
|
||||||
|
FileClose(handle);
|
||||||
|
LOGD("WTPI_LoadPersistentData: got %zd.", *data_length);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_StorePersistentData(const uint8_t* data,
|
||||||
|
size_t data_length) {
|
||||||
|
LOGD("Saving %zd bytes persistent data", data_length);
|
||||||
|
File_Handle handle =
|
||||||
|
FileOpen(kPersistentDataPath, FILE_OPEN_CREATE | FILE_OPEN_TRUNCATE);
|
||||||
|
if (handle == NULL) {
|
||||||
|
LOGE("Failed to open file %s", kPersistentDataPath);
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (FileWrite(handle, (const char*)data, data_length) != (int)data_length) {
|
||||||
|
LOGE("Failed to save persistent data");
|
||||||
|
FileClose(handle);
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
FileClose(handle);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,479 @@
|
|||||||
|
/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_crypto_and_key_management_interface_layer2.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "crypto_util.h"
|
||||||
|
#include "layer2_crypto_key_table.h"
|
||||||
|
#include "odk_util.h"
|
||||||
|
#include "oemcrypto_compiler_attributes.h"
|
||||||
|
#include "oemcrypto_key_types.h"
|
||||||
|
#include "oemcrypto_math.h"
|
||||||
|
#include "oemcrypto_overflow.h"
|
||||||
|
#include "openssl/aes.h"
|
||||||
|
#include "openssl/bio.h"
|
||||||
|
#include "openssl/cmac.h"
|
||||||
|
#include "openssl/evp.h"
|
||||||
|
#include "openssl/hmac.h"
|
||||||
|
#include "openssl/rand.h"
|
||||||
|
#include "openssl/rsa.h"
|
||||||
|
#include "openssl/x509.h"
|
||||||
|
#include "rsa_util.h"
|
||||||
|
#include "wtpi_abort_interface.h"
|
||||||
|
#include "wtpi_device_key_access_interface.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This is a test implementation of Crypto and Key Management layer 2,
|
||||||
|
* which simulates a hardware-backed cryptography. The keys stored in a
|
||||||
|
* pre-allocated table with limited number of slots. OpenSSL is used here as a
|
||||||
|
* replacement of the hardware crypto.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct wtpi_k2_symmetric_key_handle {
|
||||||
|
uint32_t index;
|
||||||
|
} wtpi_k2_symmetric_key_handle;
|
||||||
|
|
||||||
|
bool WTPI_K2_IsKeyHandleValid(WTPI_K2_SymmetricKey_Handle key_handle) {
|
||||||
|
return ((key_handle != NULL) && K2_IsKeyValid(key_handle->index));
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_GetKeyType(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
SymmetricKeyType* type) {
|
||||||
|
if (key_handle == NULL || type == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
*type = K2_GetKeyType(key_handle->index);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_GetKeySize(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
KeySize* size) {
|
||||||
|
if (key_handle == NULL || size == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
*size = K2_GetKeySize(key_handle->index);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_InitializeKeyManagement(void) {
|
||||||
|
return K2_InitializeKeyTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_TerminateKeyManagement(void) {
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
The following implement the key mapping interface.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
bool KM_IsLayer2KeyIndexValid(uint32_t k2_index) {
|
||||||
|
return K2_IsIndexValid(k2_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult KM_GetLayer2KeyIndex(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
uint32_t* k2_index) {
|
||||||
|
if (key_handle == NULL || k2_index == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
*k2_index = key_handle->index;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KM_SetLayer2KeyEvictionCallback(OEMCryptoResult (*callback)(uint32_t)) {
|
||||||
|
K2_SetEvictionCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
The following implement the layer 2 crypto interface.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_AESCBCEncrypt(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
const uint8_t* in, size_t in_length,
|
||||||
|
const uint8_t* iv, uint8_t* out) {
|
||||||
|
if (key_handle == NULL || in == NULL || in_length == 0 ||
|
||||||
|
in_length % AES_BLOCK_SIZE != 0 || iv == NULL || out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (!OPKI_AESCBCEncrypt(in, in_length, iv, key, (size_t)key_size, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OEMCryptoResult DeriveKeyWithCMACToKeyHandle(
|
||||||
|
const uint8_t* key, KeySize key_size, uint8_t counter,
|
||||||
|
const uint8_t* context, size_t context_length,
|
||||||
|
SymmetricKeyType out_key_type, KeySize out_key_size,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_key_handle) {
|
||||||
|
if ((out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256) ||
|
||||||
|
context == NULL || context_length <= 0 || out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t buffer[KEY_SIZE_256];
|
||||||
|
if (!OPKI_DeriveKeyWithCMAC(key, key_size, counter, context, context_length,
|
||||||
|
out_key_size, buffer)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return WTPI_K2_CreateKeyHandle(buffer, out_key_size, out_key_type,
|
||||||
|
out_key_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_AESCBCDecrypt(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
size_t key_length, const uint8_t* in,
|
||||||
|
size_t in_length, const uint8_t* iv,
|
||||||
|
uint8_t* out) {
|
||||||
|
if (key_handle == NULL ||
|
||||||
|
(key_length != KEY_SIZE_128 && key_length != KEY_SIZE_256) ||
|
||||||
|
in == NULL || in_length == 0 || in_length % AES_BLOCK_SIZE != 0 ||
|
||||||
|
iv == NULL || out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (key_length > K2_GetKeySize(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
if (!OPKI_AESCBCDecrypt(in, in_length, iv, key, key_length, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_AESCTRDecrypt(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
const uint8_t* in, size_t in_length,
|
||||||
|
const uint8_t* iv, size_t block_offset,
|
||||||
|
uint8_t* out) {
|
||||||
|
if (key_handle == NULL || in == NULL || in_length == 0 ||
|
||||||
|
block_offset >= AES_BLOCK_SIZE || iv == NULL || out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (!OPKI_AESCTRDecrypt(in, in_length, iv, key, (size_t)key_size,
|
||||||
|
block_offset, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_HMAC_SHA1(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
const uint8_t* message, size_t message_length,
|
||||||
|
uint8_t* out) {
|
||||||
|
if (key_handle == NULL || message == NULL || message_length == 0 ||
|
||||||
|
out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (!OPKI_HMAC_SHA1(message, message_length, key, (size_t)key_size, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_SHA256(const uint8_t* message, size_t message_length,
|
||||||
|
uint8_t* out) {
|
||||||
|
if (message == NULL || message_length == 0 || out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!SHA256(message, message_length, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_HMAC_SHA256(WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
const uint8_t* message,
|
||||||
|
size_t message_length, uint8_t* out) {
|
||||||
|
if (key_handle == NULL || message == NULL || message_length == 0 ||
|
||||||
|
out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!K2_IsKeyValid(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (!OPKI_HMAC_SHA256(message, message_length, key, (size_t)key_size, out)) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_HMAC_SHA256_Verify(
|
||||||
|
WTPI_K2_SymmetricKey_Handle key_handle, const uint8_t* message,
|
||||||
|
size_t message_length, const uint8_t* signature) {
|
||||||
|
if (signature == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
||||||
|
OEMCryptoResult result = WTPI_C2_HMAC_SHA256(
|
||||||
|
key_handle, message, message_length, computed_signature);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
if (crypto_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) {
|
||||||
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_C2_RandomBytes(uint8_t* out, size_t size) {
|
||||||
|
if (out == NULL || size == 0) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
if (RAND_bytes(out, (int)size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
The following implement the layer 2 key management interface.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_CreateKeyHandle(
|
||||||
|
const uint8_t* serialized_bytes, size_t size, SymmetricKeyType key_type,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_key_handle) {
|
||||||
|
if (serialized_bytes == NULL || size == 0 || out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (size != KEY_SIZE_128 && size != KEY_SIZE_256) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
WTPI_K2_SymmetricKey_Handle handle =
|
||||||
|
malloc(sizeof(wtpi_k2_symmetric_key_handle));
|
||||||
|
if (handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
uint32_t index;
|
||||||
|
OEMCryptoResult result = K2_AddKey(serialized_bytes, size, key_type, &index);
|
||||||
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
|
free(handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
handle->index = index;
|
||||||
|
*out_key_handle = handle;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_DeriveDeviceKeyIntoHandle(
|
||||||
|
uint32_t context, SymmetricKeyType out_key_type,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) {
|
||||||
|
if (out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
const uint8_t* device_key = WTPI_GetDeviceKey();
|
||||||
|
KeySize device_key_size = WTPI_GetDeviceKeySize();
|
||||||
|
WTPI_K2_SymmetricKey_Handle temp_key_handle = NULL;
|
||||||
|
OEMCryptoResult result = WTPI_K2_CreateKeyHandle(
|
||||||
|
device_key, device_key_size, DERIVING_KEY, &temp_key_handle);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
// Prepare full context for key derivation
|
||||||
|
// Server and client MAC keys must derive to the same key.
|
||||||
|
const SymmetricKeyType type_temp =
|
||||||
|
out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type;
|
||||||
|
// Cast the type into 32 bits so it is the same size as the gap left for it in
|
||||||
|
// full_context. This will be a no-op on most architectures.
|
||||||
|
const uint32_t type_32 = (uint32_t)type_temp;
|
||||||
|
// Build a full context that is unique to this starting context / key type
|
||||||
|
// combination. We start with a context template with blanks at the beginning
|
||||||
|
// and fill the blanks with the starting context and key type.
|
||||||
|
uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i',
|
||||||
|
'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'};
|
||||||
|
const size_t context_length = sizeof(full_context);
|
||||||
|
memcpy(full_context, &context, 4);
|
||||||
|
memcpy(full_context + 4, &type_32, 4);
|
||||||
|
const uint8_t counter = 1;
|
||||||
|
result = WTPI_K2_DeriveKeyFromKeyHandle(
|
||||||
|
temp_key_handle, counter, (const uint8_t*)full_context, context_length,
|
||||||
|
out_key_type, out_key_size, out_key_handle);
|
||||||
|
WTPI_K2_FreeKeyHandle(temp_key_handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_AESDecryptAndCreateKeyHandle(
|
||||||
|
WTPI_K2_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key,
|
||||||
|
size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_key_handle) {
|
||||||
|
if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 ||
|
||||||
|
iv == NULL || out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (enc_key_length != KEY_SIZE_128 && enc_key_length != KEY_SIZE_256) {
|
||||||
|
/* Generic crypto allows both key sizes. */
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(decrypt_key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t raw_key[KEY_SIZE_256];
|
||||||
|
KeySize key_size;
|
||||||
|
OEMCryptoResult result = WTPI_K2_GetKeySize(decrypt_key_handle, &key_size);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
result = WTPI_C2_AESCBCDecrypt(decrypt_key_handle, (size_t)key_size, enc_key,
|
||||||
|
enc_key_length, iv, raw_key);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
WTPI_K2_SymmetricKey_Handle handle = NULL;
|
||||||
|
result = WTPI_K2_CreateKeyHandle(raw_key, enc_key_length, key_type, &handle);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
*out_key_handle = handle;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_AESDecryptAndCreateKeyHandleForMacKeys(
|
||||||
|
WTPI_K2_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys,
|
||||||
|
size_t enc_mac_keys_length, const uint8_t* iv,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_mac_key_server,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_mac_key_client) {
|
||||||
|
if (decrypt_key_handle == NULL || enc_mac_keys == NULL ||
|
||||||
|
enc_mac_keys_length == 0 || iv == NULL || out_mac_key_server == NULL ||
|
||||||
|
out_mac_key_client == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (enc_mac_keys_length != 2 * MAC_KEY_SIZE) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(decrypt_key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t raw_mac_keys[2 * MAC_KEY_SIZE];
|
||||||
|
KeySize key_size;
|
||||||
|
OEMCryptoResult result = WTPI_K2_GetKeySize(decrypt_key_handle, &key_size);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
result =
|
||||||
|
WTPI_C2_AESCBCDecrypt(decrypt_key_handle, (size_t)key_size, enc_mac_keys,
|
||||||
|
enc_mac_keys_length, iv, raw_mac_keys);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
WTPI_K2_SymmetricKey_Handle server_handle = NULL;
|
||||||
|
result = WTPI_K2_CreateKeyHandle(raw_mac_keys, MAC_KEY_SIZE, MAC_KEY_SERVER,
|
||||||
|
&server_handle);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
WTPI_K2_SymmetricKey_Handle client_handle = NULL;
|
||||||
|
result = WTPI_K2_CreateKeyHandle(raw_mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE,
|
||||||
|
MAC_KEY_CLIENT, &client_handle);
|
||||||
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
|
WTPI_K2_FreeKeyHandle(server_handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*out_mac_key_server = server_handle;
|
||||||
|
*out_mac_key_client = client_handle;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_DeriveKeyFromKeyHandle(
|
||||||
|
WTPI_K2_SymmetricKey_Handle key_handle, uint8_t counter,
|
||||||
|
const uint8_t* context, size_t context_length,
|
||||||
|
SymmetricKeyType out_key_type, KeySize out_key_size,
|
||||||
|
WTPI_K2_SymmetricKey_Handle* out_key_handle) {
|
||||||
|
if (key_handle == NULL || context == NULL || context_length == 0 ||
|
||||||
|
out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (K2_GetKeyType(key_handle->index) != DERIVING_KEY) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
return DeriveKeyWithCMACToKeyHandle(key, key_size, counter, context,
|
||||||
|
context_length, out_key_type,
|
||||||
|
out_key_size, out_key_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_WrapKey(uint32_t context,
|
||||||
|
WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
SymmetricKeyType key_type, uint8_t* wrapped_key,
|
||||||
|
size_t wrapped_key_length) {
|
||||||
|
if (key_handle == NULL || wrapped_key == NULL || wrapped_key_length == 0) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (key_type != K2_GetKeyType(key_handle->index)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
if (wrapped_key_length != key_size) {
|
||||||
|
/* The caller should give us the correct buffer size. */
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
|
||||||
|
/* TODO(b/158766099): encrypt the data instead of memcpy. */
|
||||||
|
memcpy(wrapped_key, key, key_size);
|
||||||
|
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_UnwrapIntoKeyHandle(
|
||||||
|
uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length,
|
||||||
|
SymmetricKeyType key_type, WTPI_K2_SymmetricKey_Handle* out_key_handle) {
|
||||||
|
if (wrapped_key == NULL || wrapped_key_length == 0 ||
|
||||||
|
out_key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (wrapped_key_length != KEY_SIZE_128 &&
|
||||||
|
wrapped_key_length != KEY_SIZE_256) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO(b/158766099): decrypt the key data before creating key handle. */
|
||||||
|
|
||||||
|
return WTPI_K2_CreateKeyHandle(wrapped_key, wrapped_key_length, key_type,
|
||||||
|
out_key_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_EncryptKeyHandle(
|
||||||
|
WTPI_K2_SymmetricKey_Handle key_handle,
|
||||||
|
WTPI_K2_SymmetricKey_Handle encrypt_key_handle, const uint8_t* iv,
|
||||||
|
uint8_t* out) {
|
||||||
|
if (key_handle == NULL || encrypt_key_handle == NULL || iv == NULL ||
|
||||||
|
out == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
uint8_t* key = K2_GetKey(key_handle->index);
|
||||||
|
KeySize key_size = K2_GetKeySize(key_handle->index);
|
||||||
|
|
||||||
|
return WTPI_C2_AESCBCEncrypt(encrypt_key_handle, key, key_size, iv, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_K2_FreeKeyHandle(WTPI_K2_SymmetricKey_Handle key_handle) {
|
||||||
|
if (key_handle == NULL) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
OEMCryptoResult result = K2_RemoveKey(key_handle->index);
|
||||||
|
free(key_handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_device_renewal_interface_layer2.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "oemcrypto_check_macros.h"
|
||||||
|
#include "oemcrypto_key_types.h"
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetRenewalInfo(uint32_t old_system_id,
|
||||||
|
uint32_t* new_system_id,
|
||||||
|
uint8_t* renewal_key,
|
||||||
|
size_t renewal_key_length) {
|
||||||
|
ABORT_IF(old_system_id != 0x1ee8, "Unexpected old system ID");
|
||||||
|
ABORT_IF_NULL(new_system_id);
|
||||||
|
ABORT_IF_NULL(renewal_key);
|
||||||
|
ABORT_IF(renewal_key_length != KEY_SIZE_128, "Unexpected renewal key size");
|
||||||
|
|
||||||
|
// The following magic values map to the renewal twin of the test keybox and
|
||||||
|
// were exchanged with the provisioning team out-of-band.
|
||||||
|
*new_system_id = 25421;
|
||||||
|
static const uint8_t kRenewalKey[KEY_SIZE_128] = {
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||||
|
};
|
||||||
|
memcpy(renewal_key, kRenewalKey, KEY_SIZE_128);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_clock_interface_layer2.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "wtpi_initialize_terminate_interface.h"
|
||||||
|
#include "wtpi_logging_interface.h"
|
||||||
|
|
||||||
|
// This implementation is used when we do not have access to a clock that can do
|
||||||
|
// fake sleeps.
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetSecureTimer(uint64_t* time_in_s) {
|
||||||
|
if (!time_in_s) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
*time_in_s = time(0);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_Initialize(void) {
|
||||||
|
LOGD("WTPI_Initialize.");
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_Terminate(void) {
|
||||||
|
LOGD("WTPI_Terminate.");
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
source code may only be used and distributed under the Widevine
|
||||||
|
License Agreement. */
|
||||||
|
|
||||||
|
#include "wtpi_config_interface.h"
|
||||||
|
|
||||||
|
OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) {
|
||||||
|
return OEMCrypto_Level3;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) {
|
||||||
|
#ifdef USE_PROVISIONING_40
|
||||||
|
return OEMCrypto_BootCertificateChain;
|
||||||
|
#else
|
||||||
|
return OEMCrypto_Keybox;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WTPI_GetResourceRatingTier(void) { return 3; }
|
||||||
|
|
||||||
|
OPK_FeatureStatus WTPI_IsTAAntiRollbackEnabled(void) {
|
||||||
|
return OPK_FEATURE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WTPI_IsProductionReady(void) { return false; }
|
||||||
|
|
||||||
|
OEMCrypto_WatermarkingSupport WTPI_GetWatermarkingSupport(void) {
|
||||||
|
return OEMCrypto_WatermarkingNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCrypto_DTCP2_Capability WTPI_GetDTCP2Capability(void) {
|
||||||
|
return OEMCrypto_NO_DTCP2;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) {
|
||||||
|
if (srm_version == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
*srm_version = 0;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WTPI_IsAntiRollbackHWPresent() { return false; }
|
||||||
|
|
||||||
|
OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field) {
|
||||||
|
/* No CGMS for test impl. */
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WTPI_IsCGMS_AActive(void) { return false; }
|
||||||
|
|
||||||
|
bool WTPI_SupportsCGMS_A(void) { return false; }
|
||||||
|
|
||||||
|
bool WTPI_HasAnalogDisplay(void) { return false; }
|
||||||
|
|
||||||
|
bool WTPI_IsAnalogDisplayActive(void) { return false; }
|
||||||
|
|
||||||
|
bool WTPI_CanDisableAnalogDisplay(void) { return false; }
|
||||||
|
|
||||||
|
bool WTPI_DisableAnalogDisplay(void) { return false; }
|
||||||
|
|
||||||
|
size_t WTPI_MaxBufferSizeForDecrypt(void) {
|
||||||
|
return 1 * 1024 * 1024; /* 1 MiB according to resource rating tier. */
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_MaxOutputSizeForDecrypt(void) { return 0; /* Unrestricted. */ }
|
||||||
|
|
||||||
|
bool WTPI_IsClosedPlatform(void) { return false; }
|
||||||
|
|
||||||
|
OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) {
|
||||||
|
return HDCP_NO_DIGITAL_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) {
|
||||||
|
return HDCP_NO_DIGITAL_OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_MaxBufferSizeForGenericCrypto(void) {
|
||||||
|
return 500 * 1024; /* 500 KiB according to resource rating tier. */
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WTPI_MaxSampleSize(void) {
|
||||||
|
return 16 * 1024 * 1024; /* 16 MiB according to resource rating tier. */
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t WTPI_SupportedCertificates(void) {
|
||||||
|
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
||||||
|
OEMCrypto_Supports_ECC_secp256r1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# Copyright 2021 Google LLC.All Rights Reserved.This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
|
||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
'oemcrypto_ta_dir' : '<(DEPTH)/oemcrypto/opk/oemcrypto_ta',
|
||||||
|
'odk_dir' : '<(DEPTH)/oemcrypto/odk',
|
||||||
|
# Include directory that contains wtpi_config_macros.h.
|
||||||
|
'config_macros_header_dir%': '<(oemcrypto_ta_dir)/wtpi_reference',
|
||||||
|
# TODO(b/207176111): add test scripts to cover both reference crypto impl
|
||||||
|
'reference_crypto_impl%': 'software',
|
||||||
|
'test_renewal%': 0,
|
||||||
|
# Path to wtpi implementations that pass tests but are unsuitable for
|
||||||
|
# production use.
|
||||||
|
'wtpi_stub_dir': '<(oemcrypto_ta_dir)/wtpi_useless',
|
||||||
|
'use_provisioning_40%': 0,
|
||||||
|
},
|
||||||
|
'target_defaults': {
|
||||||
|
'toolsets' : [ 'target' ],
|
||||||
|
'type': 'static_library',
|
||||||
|
'include_dirs': [
|
||||||
|
'<(config_macros_header_dir)',
|
||||||
|
'<(DEPTH)/util/include',
|
||||||
|
'test-only',
|
||||||
|
'.',
|
||||||
|
'<(odk_dir)/include',
|
||||||
|
],
|
||||||
|
'sources': [
|
||||||
|
'wtpi_oemcrypto_config.c',
|
||||||
|
'test-only/wtpi_persistent_storage.c',
|
||||||
|
'test-only/file_store_interface.c',
|
||||||
|
'test-only/wtpi_cas.c',
|
||||||
|
'test-only/wtpi_device_key_access.c',
|
||||||
|
'<(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c',
|
||||||
|
'<(wtpi_stub_dir)/wtpi_secure_buffer_access.c',
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['reference_crypto_impl=="hardware"', {
|
||||||
|
'sources': [
|
||||||
|
'layer2_crypto_key_table.c',
|
||||||
|
'wtpi_crypto_and_key_management_layer2_hw.c',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['test_renewal', {
|
||||||
|
'sources': [
|
||||||
|
'wtpi_device_renewal_layer2_test.c',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['use_provisioning_40', {
|
||||||
|
'defines': [
|
||||||
|
'USE_PROVISIONING_40',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_linux_tee',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_abort',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_clock',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_crypto',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_idle',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_logging',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_renewal',
|
||||||
|
'<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_root_of_trust',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets': [{
|
||||||
|
# This target is used when we have the serialization IPC in the loop. In
|
||||||
|
# that case, we cannot use a fake clock.
|
||||||
|
'target_name': 'oemcrypto_ta_test_impl_ipc',
|
||||||
|
'sources': [
|
||||||
|
'wtpi_init_and_clock_ipc.c',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# This target is used when we do not have the serialization IPC in the
|
||||||
|
# loop. In that case, we can use a fake clock, but we also don't have the
|
||||||
|
# serialization level telling us what the wall clock.
|
||||||
|
'target_name': 'oemcrypto_ta_test_impl_no_ipc',
|
||||||
|
'sources': [
|
||||||
|
'test-only/wtpi_init_and_clock_no_ipc.cpp',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
56
oemcrypto/opk/ports/linux/ta/oemcrypto_ta/Makefile
Normal file
56
oemcrypto/opk/ports/linux/ta/oemcrypto_ta/Makefile
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This Makefile is not intended to be invoked on its own. It is possible
|
||||||
|
# though. Be sure to set the following variables.
|
||||||
|
# - CDM_DIR: path to top of CDM repo
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# Define this for tee-sources.mk, which uses it as a prefix for source file
|
||||||
|
# locations
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
# tee-sources.mk provides opk_base_ta_sources and opk_base_ta_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
# Definitions for wtpi_impl sources.mk
|
||||||
|
wtpi_impl_dir := $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl
|
||||||
|
|
||||||
|
# Provides wtpi_impl_sources and wtpi_impl_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk
|
||||||
|
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/clock.cpp \
|
||||||
|
$(tos_impl_dir)/tos_shared_memory.cpp \
|
||||||
|
$(opk_base_ta_sources) \
|
||||||
|
$(wtpi_impl_sources) \
|
||||||
|
$(boringssl_sources) \
|
||||||
|
$(dice_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common \
|
||||||
|
$(OPK_REPO_TOP)/util/include \
|
||||||
|
$(opk_base_ta_includes) \
|
||||||
|
$(wtpi_impl_includes) \
|
||||||
|
$(boringssl_includes) \
|
||||||
|
$(dice_includes) \
|
||||||
|
|
||||||
|
cflags += \
|
||||||
|
-DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"$(project)\" \
|
||||||
|
-D_DEFAULT_SOURCE
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -lpthread \
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
|
|
||||||
23
oemcrypto/opk/ports/linux/ta/tee_simulator/README.md
Normal file
23
oemcrypto/opk/ports/linux/ta/tee_simulator/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Linux-IPC-Test port of the OPK
|
||||||
|
|
||||||
|
The linux-ipc-test port of OPK is a sample implementation of the OPK transport and
|
||||||
|
shared memory interfaces that runs in two separate linux processes to verify the
|
||||||
|
serialization and deserialization functionality. The TEE side is implemented in
|
||||||
|
a tee_simulator linux process, and the REE side implements the OEMCrypto API. The
|
||||||
|
TEE side contains the OEMCrypto TA. The REE side runs the oemcrypto test suite.
|
||||||
|
|
||||||
|
```
|
||||||
|
File structure:
|
||||||
|
./oemcrypto
|
||||||
|
build file for liboemcrypto.so
|
||||||
|
./serialization_adapter
|
||||||
|
implementation of os_interfaces/tos_transport_interface.h
|
||||||
|
implementation of os_interfaces/tos_shared_memory_interface.h
|
||||||
|
implementation of os_interfaces/opk_secure_buffer_interface.h
|
||||||
|
./serialization_adapter/test
|
||||||
|
test for the shared memory implementation
|
||||||
|
./tee_simulator
|
||||||
|
TEE main loop, calls implementation of tee_dispatcher.h
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
66
oemcrypto/opk/ports/linux/ta/wtpi_test_ta/Makefile
Normal file
66
oemcrypto/opk/ports/linux/ta/wtpi_test_ta/Makefile
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
# source code may only be used and distributed under the Widevine
|
||||||
|
# License Agreement.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This Makefile is not intended to be invoked on its own. It is possible
|
||||||
|
# though. Be sure to set the following variables.
|
||||||
|
# - CROSS_COMPILE: prefix of compiler, eg arm-linux-gnueabihf-
|
||||||
|
# - CDM_DIR: path to top of CDM repo
|
||||||
|
|
||||||
|
# Place outputs in $CDM_DIR/out/linux/<project>/
|
||||||
|
project := $(shell basename $(CURDIR))
|
||||||
|
srcdir := $(shell realpath --relative-to=$(CURDIR) $(CDM_DIR))
|
||||||
|
builddir := $(srcdir)/out/linux/$(project)/
|
||||||
|
output = $(project)
|
||||||
|
|
||||||
|
# Define this for tee-sources.mk, which uses it as a prefix for source file
|
||||||
|
# locations
|
||||||
|
OPK_REPO_TOP :=
|
||||||
|
# tee-sources.mk provides opk_base_ta_sources and opk_base_ta_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/tee-sources.mk
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/build/ree-sources.mk
|
||||||
|
|
||||||
|
# Definitions for wtpi_impl sources.mk
|
||||||
|
wtpi_impl_dir := $(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl
|
||||||
|
|
||||||
|
# Provides wtpi_impl_sources and wtpi_impl_includes
|
||||||
|
include $(CDM_DIR)/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/sources.mk
|
||||||
|
|
||||||
|
# $(info $(boringssl_sources))
|
||||||
|
|
||||||
|
# srcs-y, global-incdirs-y, and libnames are used by the OP-TEE TA dev kit
|
||||||
|
# build system
|
||||||
|
srcs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/tee_simulator.cpp \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/ta/common/clock.cpp \
|
||||||
|
$(tos_impl_dir)/tos_shared_memory.cpp \
|
||||||
|
$(oemcrypto_ta_dir)/oemcrypto_asymmetric_key_table.c \
|
||||||
|
$(oemcrypto_ta_dir)/oemcrypto_object_table.c \
|
||||||
|
$(oemcrypto_ta_dir)/oemcrypto_key.c \
|
||||||
|
$(opk_base_wtpi_ta_sources) \
|
||||||
|
$(wtpi_impl_sources) \
|
||||||
|
$(boringssl_sources) \
|
||||||
|
$(dice_sources) \
|
||||||
|
|
||||||
|
incs += \
|
||||||
|
$(OPK_REPO_TOP)/oemcrypto/opk/ports/linux/common \
|
||||||
|
$(OPK_REPO_TOP)/util/include \
|
||||||
|
$(opk_base_wtpi_ta_includes) \
|
||||||
|
$(wtpi_impl_includes) \
|
||||||
|
$(oemcrypto_ta_includes) \
|
||||||
|
$(boringssl_includes) \
|
||||||
|
$(dice_includes) \
|
||||||
|
|
||||||
|
|
||||||
|
cflags += \
|
||||||
|
-DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \
|
||||||
|
-DWV_POSIX_RESOURCE_ID=\"$(project)\" \
|
||||||
|
-D_DEFAULT_SOURCE
|
||||||
|
|
||||||
|
ldflags = \
|
||||||
|
-lrt -lpthread \
|
||||||
|
|
||||||
|
include ../../rules.mk
|
||||||
|
|
||||||
60
oemcrypto/opk/ports/linux/wtpi_tee_simulator.gyp
Normal file
60
oemcrypto/opk/ports/linux/wtpi_tee_simulator.gyp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#
|
||||||
|
# Builds tee_simulator executable, which includes Linux-based
|
||||||
|
# implementation of transport and shared memory.
|
||||||
|
#
|
||||||
|
# Dependencies:
|
||||||
|
# OPK serialization library for TEE [ 'tee.gyp:opk_tee' ]
|
||||||
|
# Implementation of porting layer API ['wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc']
|
||||||
|
{
|
||||||
|
'includes' : {
|
||||||
|
'../../oemcrypto_ta/wtpi_test/settings.gypi',
|
||||||
|
},
|
||||||
|
'variables': {
|
||||||
|
'wtpi_impl' : '<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_ipc',
|
||||||
|
'platform_specific_dir%': '<(DEPTH)/linux/src',
|
||||||
|
'tee_simulator_dir' : '<(oemcrypto_dir)/opk/ports/linux/ta/common',
|
||||||
|
'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/common',
|
||||||
|
|
||||||
|
'privacy_crypto_impl%': 'boringssl',
|
||||||
|
'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
|
||||||
|
'boringssl_libssl_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:ssl',
|
||||||
|
'gtest_dependency%': '<(DEPTH)/third_party/googletest.gyp:gtest',
|
||||||
|
'gmock_dependency%': '<(DEPTH)/third_party/googletest.gyp:gmock',
|
||||||
|
'oemcrypto_dir%': '<(DEPTH)/oemcrypto',
|
||||||
|
'util_dir%': '<(DEPTH)/util',
|
||||||
|
},
|
||||||
|
'target_defaults': {
|
||||||
|
'include_dirs' : [
|
||||||
|
'ta/common/wtpi_impl',
|
||||||
|
'<(serialization_adapter_dir)',
|
||||||
|
'<(serialization_dir)/tee/include',
|
||||||
|
'<(tee_dir)',
|
||||||
|
'<(util_dir)/include',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets' : [
|
||||||
|
{
|
||||||
|
'target_name': 'tee_simulator',
|
||||||
|
'type': 'executable',
|
||||||
|
'sources': [
|
||||||
|
'<(serialization_adapter_dir)/tos_logging.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_secure_buffers.c',
|
||||||
|
'<(serialization_adapter_dir)/tos_shared_memory.cpp',
|
||||||
|
'<(serialization_adapter_dir)/tos_transport.cpp',
|
||||||
|
'<(tee_simulator_dir)/clock.cpp',
|
||||||
|
'<(tee_simulator_dir)/tee_simulator.cpp',
|
||||||
|
'<(platform_specific_dir)/file_store.cpp',
|
||||||
|
'<(platform_specific_dir)/log.cpp',
|
||||||
|
'<(util_dir)/src/platform.cpp',
|
||||||
|
'<(util_dir)/src/rw_lock.cpp',
|
||||||
|
'<(util_dir)/src/string_conversions.cpp',
|
||||||
|
'<(util_dir)/src/string_format.cpp',
|
||||||
|
],
|
||||||
|
'dependencies': [
|
||||||
|
'<(tee_dir)/tee.gyp:opk_tee_wtpi_test',
|
||||||
|
'<(wtpi_impl)',
|
||||||
|
],
|
||||||
|
'libraries': ['-lrt', '-lpthread', '-ldl'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
46
oemcrypto/opk/ports/optee/scripts/install_ta.sh
Executable file
46
oemcrypto/opk/ports/optee/scripts/install_ta.sh
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
# Run this script in the non-secure QEMU login shell to copy the Widevine
|
||||||
|
# OEMCrypto TA and WTPI Test TA to the directory where the TAs are located and
|
||||||
|
# set environment variables to access the liboecmrypto.so
|
||||||
|
|
||||||
|
OEMCRYPTO_TA=a92d116c-ce27-4917-b30c-4a416e2d9351.ta
|
||||||
|
if test -f $OEMCRYPTO_TA; then
|
||||||
|
echo "Installing OEMCrypto TA"
|
||||||
|
cp $OEMCRYPTO_TA /lib/optee_armtz
|
||||||
|
xtest --install-ta /lib/optee_armtz/$OEMCRYPTO_TA
|
||||||
|
else
|
||||||
|
if test -f /lib/optee_armtz/$OEMCRYPTO_TA; then
|
||||||
|
echo "OEMCrypto TA is already installed"
|
||||||
|
else
|
||||||
|
echo "OEMCrypto TA not found, run push.sh from host"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
WTPI_TEST_TA=b0f42504-01ec-11ec-9a03-0242ac130003.ta
|
||||||
|
if test -f $WTPI_TEST_TA; then
|
||||||
|
echo "Installing WTPI Test TA"
|
||||||
|
cp $WTPI_TEST_TA /lib/optee_armtz
|
||||||
|
xtest --install-ta /lib/optee_armtz/$WTPI_TEST_TA
|
||||||
|
else
|
||||||
|
if test -f /lib/optee_armtz/$WTPI_TEST_TA; then
|
||||||
|
echo "WTPI Test TA is already installed"
|
||||||
|
else
|
||||||
|
echo "WTPI TEST TA not found, run push.sh from host"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# restart tee-supplicant
|
||||||
|
PID=$(ps | grep tee-supplicant | grep -v grep | sed 's/ tee.*//')
|
||||||
|
if test -z $PID; then
|
||||||
|
echo "tee-supplicant is not running"
|
||||||
|
else
|
||||||
|
echo "stopping tee-supplicant"
|
||||||
|
kill $PID
|
||||||
|
fi
|
||||||
|
echo "starting tee-supplicant"
|
||||||
|
su tee -c "tee-supplicant -d /dev/teepriv0" &
|
||||||
|
|
||||||
|
# run as "source" to get this to actually propagate to the environment
|
||||||
|
# eg. `. ./install_ta.sh` instead of just `./install_ta.sh`
|
||||||
|
export LD_LIBRARY_PATH=$(pwd)
|
||||||
|
export TOS_LOG_LEVEL=4
|
||||||
|
|
||||||
26
oemcrypto/opk/ports/optee/scripts/push.sh
Executable file
26
oemcrypto/opk/ports/optee/scripts/push.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PLATFORM=vexpress-qemu_virt
|
||||||
|
[ -z "${OPTEE_DIR}" ] && echo "Set \$OPTEE_DIR to your OPTEE SDK root. See README.md" && exit
|
||||||
|
[ -z "${CDM_DIR}" ] && echo "Set \$CDM_DIR to your CDM_DIR repo root" && exit
|
||||||
|
|
||||||
|
OUT_DIR=$CDM_DIR/out/optee/$PLATFORM
|
||||||
|
VIRTFS_DIR=$OPTEE_DIR/oemcrypto/test
|
||||||
|
|
||||||
|
test -d $VIRTFS_DIR || mkdir -p $VIRTFS_DIR
|
||||||
|
|
||||||
|
echo "copy oemcrypto_ta (a92d116c-ce27-4917-b30c-4a416e2d9351) to $VIRTFS_DIR"
|
||||||
|
cp $OUT_DIR/oemcrypto_ta/a92d116c-ce27-4917-b30c-4a416e2d9351.ta $VIRTFS_DIR
|
||||||
|
cp $OUT_DIR/oemcrypto_helloworld/oemcrypto_helloworld $VIRTFS_DIR
|
||||||
|
|
||||||
|
echo "copy wtpi_test_ta (b0f42504-01ec-11ec-9a03-0242ac130003) to $VIRTFS_DIR"
|
||||||
|
cp $OUT_DIR/wtpi_test_ta/b0f42504-01ec-11ec-9a03-0242ac130003.ta $VIRTFS_DIR
|
||||||
|
cp $OUT_DIR/wtpi_unittests/wtpi_unittests $VIRTFS_DIR
|
||||||
|
|
||||||
|
echo "copy oemcrypto unit tests to $VIRTFS_DIR"
|
||||||
|
cp $OUT_DIR/oemcrypto_unittests/oemcrypto_unittests $VIRTFS_DIR
|
||||||
|
|
||||||
|
echo "copy liboemcrypto.so to $VIRTFS_DIR"
|
||||||
|
cp $OUT_DIR/liboemcrypto/liboemcrypto.so $VIRTFS_DIR
|
||||||
|
|
||||||
|
echo "copy install_ta.sh to $VIRTFS_DIR"
|
||||||
|
cp ./install_ta.sh $VIRTFS_DIR
|
||||||
89
oemcrypto/opk/ports/optee/scripts/qemu-check.py
Normal file
89
oemcrypto/opk/ports/optee/scripts/qemu-check.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# This script starts QEMU, loads and boots Linux/OP-TEE, then runs
|
||||||
|
# a googletest exe in the guest. The return code is 0 for success, >0 for
|
||||||
|
# error.
|
||||||
|
#
|
||||||
|
# Makes some assumptions about the environment, namely the location of the
|
||||||
|
# virtfs directory (/mnt/host/oemcrypto/test) and the steps required to install
|
||||||
|
# and run the tests
|
||||||
|
#
|
||||||
|
# Must be run from $OPTEE_DIR/out/bin so that QEMU can locate the required
|
||||||
|
# bootloader binaries
|
||||||
|
#
|
||||||
|
# The following env variables are expected
|
||||||
|
# OPTEE_DIR: location of the OPTEE repo root
|
||||||
|
#
|
||||||
|
|
||||||
|
from absl import app
|
||||||
|
from absl import flags
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import pexpect
|
||||||
|
|
||||||
|
# Required
|
||||||
|
_QEMU = flags.DEFINE_string('qemu', None, 'Path to QEMU executable.')
|
||||||
|
_TEST_CMD = flags.DEFINE_string('test_cmd', None, 'Command to run once QEMU is booted and TAs are installed.')
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
_QEMU_BIOS = flags.DEFINE_string('qemu_bios', os.environ['OPTEE_DIR'] + '/out/bin/bl1.bin', 'Binary for QEMU to run.')
|
||||||
|
_QEMU_SMP = flags.DEFINE_integer('qemu_smp', 2, 'Number of cores for QEMU.')
|
||||||
|
_QEMU_GIC = flags.DEFINE_integer('qemu_gic', 2, 'General Interrupt Controller version for QEMU.')
|
||||||
|
_QEMU_MEM = flags.DEFINE_integer('qemu_mem', 1057, 'QEMU virtual memory size.')
|
||||||
|
_QUIET = flags.DEFINE_boolean('quiet', False, 'Disable TEE console output.', short_name='q')
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
|
||||||
|
# To get QEMU to print TEE output to the same screen as the REE output, log to
|
||||||
|
# a file and print the tail of that file to stdout. Unfortunately cannot
|
||||||
|
# easily do this from another pexpect context, so we cannot filter/expect the
|
||||||
|
# TEE output
|
||||||
|
tee_serial_out = "null"
|
||||||
|
if _QUIET.value == False:
|
||||||
|
tee_serial_out = "file:serial1.log"
|
||||||
|
os.system('> serial1.log')
|
||||||
|
|
||||||
|
spawn_cmd = ''
|
||||||
|
if 'aarch64' in _QEMU.value:
|
||||||
|
spawn_cmd = _QEMU.value + '-nographic -serial mon:stdio -serial ' + tee_serial_out + ' -smp ' + str(_QEMU_SMP.value) + ' -machine virt,secure=on,gic-version=' + str(_QEMU_GIC.value) + ' -cpu cortex-a57 -d unimp -semihosting-config enble=on,target=native -m ' + str(_QEMU_MEM.value) + ' -bios ' + _QEMU_BIOS.value + ' -initrd rootfs.cpio.gz -kernel Image -no-acpi -append "console=ttyAMA0,38400 keep_bootcon root=/dev/vda2" -fsdev local,id=fsdev0,path=' + os.environ['OPTEE_DIR'] + ',security_model=none -device virtio-9p-device,fsdev=fsdev0,mount_tag=host'
|
||||||
|
else:
|
||||||
|
spawn_cmd = _QEMU.value + ' -nographic -monitor none -machine virt -machine secure=on -cpu cortex-a15 -smp ' + str(_QEMU_SMP.value) + ' -d unimp -semihosting-config enable=on,target=native -m ' + str(_QEMU_MEM.value) + ' -serial stdio -serial ' + tee_serial_out + ' -bios ' + _QEMU_BIOS.value + ' -fsdev local,id=fsdev0,path=' + os.environ['OPTEE_DIR'] + ',security_model=none -device virtio-9p-device,fsdev=fsdev0,mount_tag=host'
|
||||||
|
|
||||||
|
child = pexpect.spawn(spawn_cmd, encoding='utf-8', timeout=1800)
|
||||||
|
|
||||||
|
p = None
|
||||||
|
if _QUIET.value == False:
|
||||||
|
p =subprocess.Popen(['tail', '-f', 'serial1.log'])
|
||||||
|
|
||||||
|
child.logfile = sys.stdout
|
||||||
|
i = child.expect(['Kernel panic', 'ogin:'])
|
||||||
|
if i==0:
|
||||||
|
print("Kernel panic!")
|
||||||
|
child.terminate()
|
||||||
|
if _QUIET.value == False:
|
||||||
|
p.kill()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
child.sendline('root')
|
||||||
|
child.expect('# ')
|
||||||
|
child.sendline('cd /mnt/host/oemcrypto/test')
|
||||||
|
child.expect('# ')
|
||||||
|
child.sendline('. ./install_ta.sh')
|
||||||
|
child.expect('# ')
|
||||||
|
child.sendline(_TEST_CMD.value)
|
||||||
|
|
||||||
|
i = child.expect(['^.*su tee -c "tee-supplicant -d /dev/teepriv0"','([^ ]+) FAILED TEST', 'rcu_sched detected stalls', '^.*not found' ])
|
||||||
|
if i>0: # Only the 0th element ("su tee etc") is a success case
|
||||||
|
child.terminate()
|
||||||
|
if _QUIET.value == False:
|
||||||
|
p.kill()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
child.terminate()
|
||||||
|
if _QUIET.value == False:
|
||||||
|
p.kill()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
flags.mark_flag_as_required('qemu')
|
||||||
|
flags.mark_flag_as_required('test_cmd')
|
||||||
|
app.run(main)
|
||||||
17
oemcrypto/opk/ports/optee/scripts/qemu-check.py.vpython
Normal file
17
oemcrypto/opk/ports/optee/scripts/qemu-check.py.vpython
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
python_version: "3.8"
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/pexpect/${vpython_platform}"
|
||||||
|
version: "version:4.8.0.chromium.1"
|
||||||
|
>
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/six-py2_py3"
|
||||||
|
version: "version:1.10.0"
|
||||||
|
>
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/absl-py-py3"
|
||||||
|
version: "version:0.11.0"
|
||||||
|
>
|
||||||
|
|
||||||
17
oemcrypto/opk/ports/optee/scripts/qemu-check.py.vpython3
Normal file
17
oemcrypto/opk/ports/optee/scripts/qemu-check.py.vpython3
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
python_version: "3.8"
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/pexpect/${vpython_platform}"
|
||||||
|
version: "version:4.8.0.chromium.1"
|
||||||
|
>
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/six-py2_py3"
|
||||||
|
version: "version:1.10.0"
|
||||||
|
>
|
||||||
|
|
||||||
|
wheel: <
|
||||||
|
name: "infra/python/wheels/absl-py-py3"
|
||||||
|
version: "version:0.11.0"
|
||||||
|
>
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WTPI_CRYPTO_COMMON_H_
|
||||||
|
#define _WTPI_CRYPTO_COMMON_H_
|
||||||
|
|
||||||
|
#include "wtpi_crypto_and_key_management_interface_layer1.h"
|
||||||
|
|
||||||
|
typedef struct wtpi_k1_symmetric_key_handle {
|
||||||
|
uint8_t* key;
|
||||||
|
uint32_t key_size; // TODO: change to KeySize type
|
||||||
|
SymmetricKeyType key_type;
|
||||||
|
TEE_OperationHandle op_cbc;
|
||||||
|
TEE_OperationHandle op_ecb; // Used for CTR and CBC. We don't know which will
|
||||||
|
// be used up front, so pre-allocate both for
|
||||||
|
// CONTENT_KEY types
|
||||||
|
} wtpi_k1_symmetric_key_handle;
|
||||||
|
|
||||||
|
OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key,
|
||||||
|
const uint8_t* input,
|
||||||
|
uint8_t* output);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 "special_case_request_handlers.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "GEN_tee_serializer.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "log_macros.h"
|
||||||
|
#include "marshaller_base.h"
|
||||||
|
#include "tee_special_cases.h"
|
||||||
|
|
||||||
|
void OPK_Init_OEMCrypto_EntitledContentKeyObject(
|
||||||
|
OEMCrypto_EntitledContentKeyObject* obj);
|
||||||
|
|
||||||
|
bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
|
||||||
|
ODK_Message* response) {
|
||||||
|
size_t message_length;
|
||||||
|
OPK_Init_size_t((size_t*)&message_length);
|
||||||
|
OEMCrypto_SESSION session;
|
||||||
|
OPK_Init_uint32_t((uint32_t*)&session);
|
||||||
|
uint8_t* message;
|
||||||
|
OPK_InitPointer((uint8_t**)&message);
|
||||||
|
OEMCrypto_EntitledContentKeyObject* even_key =
|
||||||
|
(OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc(
|
||||||
|
sizeof(OEMCrypto_EntitledContentKeyObject));
|
||||||
|
OPK_Init_OEMCrypto_EntitledContentKeyObject(
|
||||||
|
(OEMCrypto_EntitledContentKeyObject*)even_key);
|
||||||
|
OEMCrypto_EntitledContentKeyObject* odd_key =
|
||||||
|
(OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc(
|
||||||
|
sizeof(OEMCrypto_EntitledContentKeyObject));
|
||||||
|
OPK_Init_OEMCrypto_EntitledContentKeyObject(
|
||||||
|
(OEMCrypto_EntitledContentKeyObject*)odd_key);
|
||||||
|
OPK_Unpack_LoadCasECMKeys_Request(request, &session, &message,
|
||||||
|
&message_length, &even_key, &odd_key);
|
||||||
|
if (!ODK_Message_IsValid(request)) return false;
|
||||||
|
OEMCryptoResult result;
|
||||||
|
OPK_Init_uint32_t((uint32_t*)&result);
|
||||||
|
LOGD("LoadCasECMKeys");
|
||||||
|
result = OEMCrypto_LoadCasECMKeys(session, message, message_length, even_key,
|
||||||
|
odd_key);
|
||||||
|
*response = OPK_Pack_LoadCasECMKeys_Response(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
* source code may only be used and distributed under the Widevine
|
||||||
|
* License Agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPK_SPECIAL_CASE_REQUEST_HANDLERS_H_
|
||||||
|
#define OPK_SPECIAL_CASE_REQUEST_HANDLERS_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "odk_message.h"
|
||||||
|
|
||||||
|
bool Handle_OEMCrypto_LoadCasECMKeys(ODK_Message* request,
|
||||||
|
ODK_Message* response);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // OPK_SPECIAL_CASE_REQUEST_HANDLERS_H_
|
||||||
84
oemcrypto/opk/setup.sh
Executable file
84
oemcrypto/opk/setup.sh
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# This script downloads required dependencies to /third_party
|
||||||
|
|
||||||
|
if [ -z "$CDM_DIR" ]; then
|
||||||
|
export CDM_DIR="$(readlink -e $(dirname $0)/../..)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
download() {
|
||||||
|
REPO_URL=$1
|
||||||
|
FOLDER_NAME=$2
|
||||||
|
CHECKOUT_VAL=$3
|
||||||
|
|
||||||
|
if [ -d "$FOLDER_NAME" ]; then
|
||||||
|
echo "$FOLDER_NAME already exists, skipping"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git clone $REPO_URL $FOLDER_NAME
|
||||||
|
pushd $FOLDER_NAME
|
||||||
|
git checkout $CHECKOUT_VAL
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_boringssl() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
mkdir -p boringssl && cd boringssl
|
||||||
|
mkdir -p kit && cd kit
|
||||||
|
|
||||||
|
# e1b8685770d0e82e5a4a3c5d24ad1602e05f2e83 is the latest tested BoringSSL
|
||||||
|
download https://boringssl.googlesource.com/boringssl src e1b8685770d0e82e5a4a3c5d24ad1602e05f2e83
|
||||||
|
|
||||||
|
# generate boringssl source file list
|
||||||
|
echo "Generating boringssl source file list"
|
||||||
|
python3 ./src/util/generate_build_files.py android
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_googletest() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
if [ -d "googletest" ]; then return
|
||||||
|
fi
|
||||||
|
git clone --depth 1 https://github.com/google/googletest.git googletest
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_jsmn() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
download https://github.com/zserge/jsmn.git jsmn v1.0.0
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_cosec() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
download https://pigweed.googlesource.com/third_party/github/cose-wg/COSE-C COSE-C 97d1805e71b7a6770093c5e6790d46611680d563
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_cncbor() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
download https://pigweed.googlesource.com/third_party/github/jimsch/cn-cbor cn-cbor f713bf67bcf3e076d47e474ce060252ef8be48c7
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
download_opendice() {
|
||||||
|
pushd $CDM_DIR/third_party
|
||||||
|
download https://pigweed.googlesource.com/open-dice/ open-dice 55a2cda
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_third_party() {
|
||||||
|
pushd $CDM_DIR
|
||||||
|
mkdir -p third_party
|
||||||
|
|
||||||
|
download_googletest
|
||||||
|
download_boringssl
|
||||||
|
download_jsmn
|
||||||
|
download_cosec
|
||||||
|
download_cncbor
|
||||||
|
download_opendice
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_third_party
|
||||||
|
|
||||||
306
oemcrypto/test/GEN_api_lock_file.c
Normal file
306
oemcrypto/test/GEN_api_lock_file.c
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
|
// source code may only be used and distributed under the Widevine License
|
||||||
|
// Agreement.
|
||||||
|
//
|
||||||
|
// This code is semi-auto-generated, do not edit unless you know what you are
|
||||||
|
// doing. The script oemcrypto/lock-api-for-release will append to this file.
|
||||||
|
//
|
||||||
|
// If this file does not build, then you have modified an OEMCrypto API
|
||||||
|
// function. Instead, you should rename the old function and give the modified
|
||||||
|
// function a new oecc number.
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
|
||||||
|
// This initial generation of this file was for v16.4, so older functions will
|
||||||
|
// not have an accurate version number.
|
||||||
|
|
||||||
|
OEMCryptoResult _oecc84(const uint8_t* sandbox_id, size_t sandbox_id_length);
|
||||||
|
OEMCryptoResult _oecc01(void);
|
||||||
|
OEMCryptoResult _oecc02(void);
|
||||||
|
OEMCryptoResult _oecc09(OEMCrypto_SESSION* session);
|
||||||
|
OEMCryptoResult _oecc10(OEMCrypto_SESSION session);
|
||||||
|
OEMCryptoResult _oecc95(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* mac_key_context,
|
||||||
|
size_t mac_key_context_length,
|
||||||
|
const OEMCrypto_SharedMemory* enc_key_context,
|
||||||
|
size_t enc_key_context_length);
|
||||||
|
OEMCryptoResult _oecc21(OEMCrypto_SESSION session,
|
||||||
|
const uint8_t* derivation_key,
|
||||||
|
size_t derivation_key_length,
|
||||||
|
const OEMCrypto_SharedMemory* mac_key_context,
|
||||||
|
size_t mac_key_context_length,
|
||||||
|
const OEMCrypto_SharedMemory* enc_key_context,
|
||||||
|
size_t enc_key_context_length);
|
||||||
|
OEMCryptoResult _oecc14(OEMCrypto_SESSION session, uint32_t* nonce);
|
||||||
|
OEMCryptoResult _oecc96(OEMCrypto_SESSION session, uint8_t* message,
|
||||||
|
size_t message_length, size_t* core_message_size,
|
||||||
|
uint8_t* signature, size_t* signature_length);
|
||||||
|
OEMCryptoResult _oecc97(OEMCrypto_SESSION session, uint8_t* message,
|
||||||
|
size_t message_length, size_t* core_message_size,
|
||||||
|
uint8_t* signature, size_t* signature_length);
|
||||||
|
OEMCryptoResult _oecc98(OEMCrypto_SESSION session, uint8_t* message,
|
||||||
|
size_t message_length, size_t* core_message_size,
|
||||||
|
uint8_t* signature, size_t* signature_length);
|
||||||
|
OEMCryptoResult _oecc55(const uint8_t* buffer, size_t buffer_length);
|
||||||
|
OEMCryptoResult _oecc83(
|
||||||
|
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 key_array_length, const OEMCrypto_KeyObject* key_array,
|
||||||
|
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
||||||
|
OEMCrypto_LicenseType license_type);
|
||||||
|
OEMCryptoResult _oecc99(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 _oecc92(
|
||||||
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||||
|
size_t key_array_length,
|
||||||
|
const OEMCrypto_EntitledContentKeyObject_V16* key_array);
|
||||||
|
OEMCryptoResult _oecc91(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 _oecc101(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 _oecc41(OEMCrypto_SESSION session,
|
||||||
|
const uint8_t* content_key_id,
|
||||||
|
size_t content_key_id_length,
|
||||||
|
uint8_t* key_control_block,
|
||||||
|
size_t* key_control_block_length);
|
||||||
|
OEMCryptoResult _oecc81(OEMCrypto_SESSION session,
|
||||||
|
const uint8_t* content_key_id,
|
||||||
|
size_t content_key_id_length,
|
||||||
|
OEMCryptoCipherMode cipher_mode);
|
||||||
|
OEMCryptoResult _oecc105(
|
||||||
|
OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||||
|
size_t samples_length, // the number of samples.
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||||
|
OEMCryptoResult _oecc93(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* data_addr,
|
||||||
|
size_t data_addr_length,
|
||||||
|
const OEMCrypto_DestBufferDesc* out_buffer_descriptor,
|
||||||
|
uint8_t subsample_flags);
|
||||||
|
OEMCryptoResult _oecc24(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* in_buffer,
|
||||||
|
size_t in_buffer_length, const uint8_t* iv,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
OEMCrypto_SharedMemory* out_buffer);
|
||||||
|
OEMCryptoResult _oecc25(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* in_buffer,
|
||||||
|
size_t in_buffer_length, const uint8_t* iv,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
OEMCrypto_SharedMemory* out_buffer);
|
||||||
|
OEMCryptoResult _oecc26(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* buffer,
|
||||||
|
size_t buffer_length, OEMCrypto_Algorithm algorithm,
|
||||||
|
OEMCrypto_SharedMemory* signature,
|
||||||
|
size_t* signature_length);
|
||||||
|
OEMCryptoResult _oecc27(OEMCrypto_SESSION session,
|
||||||
|
const OEMCrypto_SharedMemory* buffer,
|
||||||
|
size_t buffer_length, OEMCrypto_Algorithm algorithm,
|
||||||
|
const OEMCrypto_SharedMemory* signature,
|
||||||
|
size_t signature_length);
|
||||||
|
OEMCryptoResult _oecc08(const uint8_t* keybox_or_cert,
|
||||||
|
size_t keybox_or_cert_length,
|
||||||
|
uint8_t* wrapped_keybox_or_cert,
|
||||||
|
size_t* wrapped_keybox_or_cert_length,
|
||||||
|
const uint8_t* transport_key,
|
||||||
|
size_t transport_key_length);
|
||||||
|
OEMCryptoResult _oecc03(const uint8_t* keybox_or_cert,
|
||||||
|
size_t keybox_or_cert_length);
|
||||||
|
OEMCrypto_ProvisioningMethod _oecc49(void);
|
||||||
|
OEMCryptoResult _oecc05(void);
|
||||||
|
OEMCryptoResult _oecc07(uint8_t* device_id, size_t* device_id_length);
|
||||||
|
OEMCryptoResult _oecc04(uint8_t* key_data, size_t* key_data_length);
|
||||||
|
OEMCryptoResult _oecc78(const uint8_t* buffer, size_t buffer_length);
|
||||||
|
OEMCryptoResult _oecc103(OEMCrypto_SESSION session);
|
||||||
|
OEMCryptoResult _oecc104(uint8_t* public_cert, size_t* public_cert_length);
|
||||||
|
OEMCryptoResult _oecc06(uint8_t* random_data, size_t random_data_length);
|
||||||
|
uint32_t _oecc22(void);
|
||||||
|
uint32_t _oecc108(void);
|
||||||
|
uint8_t _oecc46(void);
|
||||||
|
OEMCryptoResult _oecc44(OEMCrypto_HDCP_Capability* current,
|
||||||
|
OEMCrypto_HDCP_Capability* maximum);
|
||||||
|
bool _oecc29(void);
|
||||||
|
size_t _oecc94(void);
|
||||||
|
bool _oecc39(void);
|
||||||
|
OEMCryptoResult _oecc38(size_t* count);
|
||||||
|
OEMCryptoResult _oecc37(size_t* max);
|
||||||
|
uint32_t _oecc52(void);
|
||||||
|
bool _oecc53(void);
|
||||||
|
OEMCryptoResult _oecc54(uint16_t* version);
|
||||||
|
uint32_t _oecc71(void);
|
||||||
|
uint32_t _oecc85(void);
|
||||||
|
OEMCryptoResult _oecc102(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 _oecc107(OEMCrypto_SESSION session,
|
||||||
|
OEMCrypto_PrivateKeyType key_type,
|
||||||
|
const uint8_t* wrapped_private_key,
|
||||||
|
size_t wrapped_private_key_length);
|
||||||
|
OEMCryptoResult _oecc45(void);
|
||||||
|
OEMCryptoResult _oecc36(OEMCrypto_SESSION session, const uint8_t* message,
|
||||||
|
size_t message_length, uint8_t* signature,
|
||||||
|
size_t* signature_length,
|
||||||
|
RSA_Padding_Scheme padding_scheme);
|
||||||
|
OEMCryptoResult _oecc61(uint8_t* header_buffer, size_t* header_buffer_length);
|
||||||
|
OEMCryptoResult _oecc62(const uint8_t* buffer, size_t buffer_length);
|
||||||
|
OEMCryptoResult _oecc63(OEMCrypto_SESSION session,
|
||||||
|
uint32_t* usage_entry_number);
|
||||||
|
OEMCryptoResult _oecc64(OEMCrypto_SESSION session, uint32_t usage_entry_number,
|
||||||
|
const uint8_t* buffer, size_t buffer_length);
|
||||||
|
OEMCryptoResult _oecc65(OEMCrypto_SESSION session,
|
||||||
|
OEMCrypto_SharedMemory* header_buffer,
|
||||||
|
size_t* header_buffer_length,
|
||||||
|
OEMCrypto_SharedMemory* entry_buffer,
|
||||||
|
size_t* entry_buffer_length);
|
||||||
|
OEMCryptoResult _oecc66(OEMCrypto_SESSION session, const uint8_t* pst,
|
||||||
|
size_t pst_length);
|
||||||
|
OEMCryptoResult _oecc32(OEMCrypto_SESSION session, const uint8_t* pst,
|
||||||
|
size_t pst_length, uint8_t* buffer,
|
||||||
|
size_t* buffer_length);
|
||||||
|
OEMCryptoResult _oecc68(OEMCrypto_SESSION session, uint32_t new_index);
|
||||||
|
OEMCryptoResult _oecc67(uint32_t new_entry_count, uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length);
|
||||||
|
OEMCryptoResult _oecc57(void);
|
||||||
|
uint32_t _oecc86(void);
|
||||||
|
OEMCryptoResult _oecc88(OEMCrypto_SESSION session, uint32_t frame_number,
|
||||||
|
const uint8_t* hash, size_t hash_length);
|
||||||
|
OEMCryptoResult _oecc89(OEMCrypto_SESSION session,
|
||||||
|
uint32_t* failed_frame_number);
|
||||||
|
OEMCryptoResult _oecc109(OEMCrypto_SESSION session, size_t buffer_size,
|
||||||
|
OEMCrypto_DestBufferDesc* output_descriptor,
|
||||||
|
int* secure_fd);
|
||||||
|
OEMCryptoResult _oecc110(OEMCrypto_SESSION session,
|
||||||
|
OEMCrypto_DestBufferDesc* output_descriptor,
|
||||||
|
int secure_fd);
|
||||||
|
OEMCryptoResult _oecc115(uint32_t* ree_major, uint32_t* ree_minor,
|
||||||
|
uint32_t* tee_major, uint32_t* tee_minor);
|
||||||
|
OEMCryptoResult _oecc113(OEMCrypto_SESSION session, uint8_t* buffer,
|
||||||
|
size_t* buffer_length, uint32_t use_test_key);
|
||||||
|
OEMCryptoResult _oecc114(OEMCrypto_SESSION session, const uint8_t* buffer,
|
||||||
|
size_t buffer_length, uint32_t use_test_key);
|
||||||
|
OEMCryptoResult _oecc13(OEMCrypto_SESSION session, const uint8_t* message,
|
||||||
|
size_t message_length, uint8_t* signature,
|
||||||
|
size_t* signature_length);
|
||||||
|
OEMCryptoResult _oecc51(OEMCrypto_SESSION session,
|
||||||
|
const uint32_t* unaligned_nonce,
|
||||||
|
const uint8_t* encrypted_message_key,
|
||||||
|
size_t encrypted_message_key_length,
|
||||||
|
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 _oecc18(OEMCrypto_SESSION session, const uint8_t* message,
|
||||||
|
size_t message_length, const uint8_t* signature,
|
||||||
|
size_t signature_length,
|
||||||
|
const uint32_t* unaligned_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 _oecc30(void);
|
||||||
|
OEMCryptoResult _oecc33(OEMCrypto_SESSION session, const uint8_t* pst,
|
||||||
|
size_t pst_length, const uint8_t* message,
|
||||||
|
size_t message_length, const uint8_t* signature,
|
||||||
|
size_t signature_length);
|
||||||
|
OEMCryptoResult _oecc43(const uint8_t* pst, size_t pst_length);
|
||||||
|
OEMCryptoResult _oecc69(OEMCrypto_SESSION session, const uint8_t* pst,
|
||||||
|
size_t pst_length);
|
||||||
|
OEMCryptoResult _oecc34(void);
|
||||||
|
OEMCryptoResult _oecc70(uint64_t time_since_license_received,
|
||||||
|
uint64_t time_since_first_decrypt,
|
||||||
|
uint64_t time_since_last_decrypt,
|
||||||
|
OEMCrypto_Usage_Entry_Status status,
|
||||||
|
uint8_t* server_mac_key, uint8_t* client_mac_key,
|
||||||
|
const uint8_t* pst, size_t pst_length);
|
||||||
|
OEMCryptoResult _oecc12(OEMCrypto_SESSION session,
|
||||||
|
const uint8_t* mac_key_context,
|
||||||
|
uint32_t mac_key_context_length,
|
||||||
|
const uint8_t* enc_key_context,
|
||||||
|
uint32_t enc_key_context_length);
|
||||||
|
OEMCryptoResult _oecc48(OEMCrypto_SESSION session, const uint8_t* data_addr,
|
||||||
|
size_t data_addr_length, bool is_encrypted,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t block_offset, // used for CTR "cenc" mode only.
|
||||||
|
OEMCrypto_DestBufferDesc* out_buffer,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||||
|
uint8_t subsample_flags);
|
||||||
|
OEMCryptoResult _oecc50(OEMCrypto_SESSION session, uint8_t* public_cert,
|
||||||
|
size_t* public_cert_length);
|
||||||
|
OEMCryptoResult _oecc19(OEMCrypto_SESSION session,
|
||||||
|
const uint8_t* wrapped_rsa_key,
|
||||||
|
size_t wrapped_rsa_key_length);
|
||||||
|
|
||||||
|
// OEMCrypto_Idle defined in v17.1
|
||||||
|
OEMCryptoResult _oecc123(OEMCrypto_IdleState state, uint32_t os_specific_code);
|
||||||
|
|
||||||
|
// OEMCrypto_Wake defined in v17.1
|
||||||
|
OEMCryptoResult _oecc124(void);
|
||||||
|
|
||||||
|
// OEMCrypto_CreateEntitledKeySession defined in v17.1
|
||||||
|
OEMCryptoResult _oecc111(OEMCrypto_SESSION oec_session,
|
||||||
|
OEMCrypto_SESSION* key_session);
|
||||||
|
|
||||||
|
// OEMCrypto_RemoveEntitledKeySession defined in v17.1
|
||||||
|
OEMCryptoResult _oecc112(OEMCrypto_SESSION key_session);
|
||||||
|
|
||||||
|
// OEMCrypto_LoadEntitledContentKeys defined in v17.1
|
||||||
|
OEMCryptoResult _oecc121(OEMCrypto_SESSION session, const uint8_t* message,
|
||||||
|
size_t message_length, size_t key_array_length,
|
||||||
|
const OEMCrypto_EntitledContentKeyObject* key_array);
|
||||||
|
|
||||||
|
// OEMCrypto_BuildInformation defined in v17.1
|
||||||
|
OEMCryptoResult _oecc125(char* buffer, size_t* buffer_length);
|
||||||
|
|
||||||
|
// OEMCrypto_SecurityLevel defined in v17.1
|
||||||
|
OEMCrypto_Security_Level _oecc126(void);
|
||||||
|
|
||||||
|
// OEMCrypto_GetDTCP2Capability defined in v17.1
|
||||||
|
OEMCryptoResult _oecc128(OEMCrypto_DTCP2_Capability* capability);
|
||||||
|
|
||||||
|
// OEMCrypto_ProductionReady defined in v17.1
|
||||||
|
OEMCryptoResult _oecc122(void);
|
||||||
|
|
||||||
|
// OEMCrypto_GetWatermarkingSupport defined in v17.1
|
||||||
|
OEMCrypto_WatermarkingSupport _oecc129(void);
|
||||||
|
|
||||||
|
// OEMCrypto_ReuseUsageEntry defined in v17.1
|
||||||
|
OEMCryptoResult _oecc127(OEMCrypto_SESSION session,
|
||||||
|
uint32_t usage_entry_number);
|
||||||
|
|
||||||
|
// OEMCrypto_GetBootCertificateChain defined in v17.1
|
||||||
|
OEMCryptoResult _oecc116(uint8_t* bcc, size_t* bcc_length,
|
||||||
|
uint8_t* additional_signature,
|
||||||
|
size_t* additional_signature_length);
|
||||||
|
|
||||||
|
// OEMCrypto_GenerateCertificateKeyPair defined in v17.1
|
||||||
|
OEMCryptoResult _oecc117(OEMCrypto_SESSION session, uint8_t* public_key,
|
||||||
|
size_t* public_key_length,
|
||||||
|
uint8_t* public_key_signature,
|
||||||
|
size_t* public_key_signature_length,
|
||||||
|
uint8_t* wrapped_private_key,
|
||||||
|
size_t* wrapped_private_key_length,
|
||||||
|
OEMCrypto_PrivateKeyType* key_type);
|
||||||
|
|
||||||
|
// OEMCrypto_InstallOemPrivateKey defined in v17.1
|
||||||
|
OEMCryptoResult _oecc118(OEMCrypto_SESSION session,
|
||||||
|
OEMCrypto_PrivateKeyType key_type,
|
||||||
|
const uint8_t* wrapped_private_key,
|
||||||
|
size_t wrapped_private_key_length);
|
||||||
|
|
||||||
|
// OEMCrypto_ReassociateEntitledKeySession defined in v17.1
|
||||||
|
OEMCryptoResult _oecc119(OEMCrypto_SESSION key_session,
|
||||||
|
OEMCrypto_SESSION oec_session);
|
||||||
|
|
||||||
|
// OEMCrypto_LoadCasECMKeys defined in v17.1
|
||||||
|
OEMCryptoResult _oecc120(OEMCrypto_SESSION session, const uint8_t* message,
|
||||||
|
size_t message_length,
|
||||||
|
const OEMCrypto_EntitledContentKeyObject* even_key,
|
||||||
|
const OEMCrypto_EntitledContentKeyObject* odd_key);
|
||||||
|
|
||||||
|
// OEMCrypto_GetOEMKeyToken defined in v17.2
|
||||||
|
OEMCryptoResult _oecc130(OEMCrypto_SESSION key_session, uint8_t* key_token,
|
||||||
|
size_t* key_token_length);
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user