Initial OPK Partner Beta v16 Release

See https://developers.google.com/widevine/drm/client/opk
for documentation and an integration guide.
This commit is contained in:
Fred Gylys-Colwell
2021-12-16 00:18:35 +00:00
parent 8e55868e8a
commit a11741f98d
183 changed files with 37369 additions and 0 deletions

46
oemcrypto/opk/FILES.md Normal file
View File

@@ -0,0 +1,46 @@
# REE-Side Serialization & IPC Files
All files are in the `serialization` directory. The REE-side code is made up of
two libraries:
## The API Library
- `api_support.c`
- `special_case_apis.c`
- `generated_src/oemcrypto_api.c`
## The Serialization Library
- `api_support.c`
- `bump_allocator.c`
- `marshaller_base.c`
- `message.c`
- `opk_serialization_base.c`
- `shared_memory_allocator.c`
- `special_cases.c`
- `generated_src/deserializer.c`
- `generated_src/dispatcher.c`
- `generated_src/serializer.c`
# TEE-Side Serialization & IPC Files
The TEE-side code consists of the same Serialization Library code as the
REE-side code.
# Trusted App Files
All files are in the `oemcrypto_ta` directory. All the files in that directory
should be part of the TA, but here is a list:
- `oemcrypto.c`
- `oemcrypto_asymmetric_key_table.c`
- `oemcrypto_endianness.c`
- `oemcrypto_key.c`
- `oemcrypto_key_table.c`
- `oemcrypto_nonce_table.c`
- `oemcrypto_overflow.c`
- `oemcrypto_session.c`
- `oemcrypto_session_key_table.c`
- `oemcrypto_session_table.c`
- `oemcrypto_usage_table.c`
- `oemcrypto_serialized_usage_table.c`

34
oemcrypto/opk/README.md Normal file
View File

@@ -0,0 +1,34 @@
# OEMCrypto Porting Kit For Trusted Execution Environments
OPK is the Widevine hardened reference implementation of OEMCrypto suitable
to run in a TEE. It is written in C with a thin porting interface to make it
easier to port to various trusted environments.
The porting interface functions are prefixed with `WTPI_`, which stands for
"Widevine TA Porting Interface".
## Current Status
This very early preview release contains an early version of the OPK source
code. It contains only the following:
1) Code for an IPC layer that implements the OEMCrypto API functions, translates
the calls into serialized objects, deserializes the objects inside the TEE,
and invokes the appropriate TA function
2) Code for a Trusted Application that implements the logic of OEMCrypto
No build system is included. No implementation of the porting layers for working
with different TEE OSes and chip hardware is included.
In addition, the code herein has the following known limitations:
1) The usage table code does not yet encrypt the usage table information.
2) The code is only sporadically and opportunistically hardened.
3) Some minor functionality is still missing, though it should all be marked
with TODO comments.
If you have received this code, Widevine is looking for your feedback! Please
let us know where it can be improved. Don't hesitate to call out things you
think we already know, particularly as regards hardening. We want to know
whether the places we see room for improvement are the same as the ones where
you do.

View File

@@ -0,0 +1,109 @@
# This is the top level makefile for a port of the OPK. It
# invokes the gyp-generated Makefile.rules, then includes the
# generated target.mk for each target library.
# The directory structure under ./build mirrors the directory
# structure rooted at the top level of the repo. This isolates all of
# the generated makefiles from the source tree so they are not
# intermingled with the source code, and can be managed/cleaned
# independently. Since these are generated files there is usually no
# need to modify these makefiles or the directory structure.
#
# The top level files are:
# Makefile.opk : This file, top level makefile for the OPK
# Makefile.rules : Generated Make rules for building the OPK
# oemcrypto.gyp : gyp file to make liboemcrypto and unit tests
# ta.gyp : gyp file with dependencies to make the TEE libraries
# The generated *.mk files contain the rules to build each library:
# ├── oemcrypto
# │ ├── odk
# │ │ └── src
# │ │ └── odk.target.mk
# │ ├── oemcrypto_unittests.target.mk
# │ └── opk
# │ ├── build
# │ │ ├── liboemcrypto.target.mk
# │ │ ├── oemcrypto_unittests.target.mk
# │ │ └── ta.target.mk
# │ ├── oemcrypto_ta
# │ │ ├── oemcrypto_ta_reference_clock.target.mk
# │ │ ├── oemcrypto_ta_reference_crypto.target.mk
# │ │ ├── oemcrypto_ta_reference_root_of_trust.target.mk
# │ │ └── oemcrypto_ta.target.mk
# │ └── serialization
# │ ├── ree
# │ │ └── opk_ree.target.mk
# │ └── tee
# │ └── opk_tee.target.mk
# └── third_party
# ├── boringssl
# │ ├── crypto.target.mk
# │ └── ssl.target.mk
# ├── gmock.target.mk
# └── gtest.target.mk
# You can add additional compiler options by setting these defines or
# passing them on the make command line:
#
# CFLAGS := <options for C only>
# CPPFLAGS := <options for C and C++>
# CXXFLAGS := <options for C++ only>
# By default, warnings are not treated as errors, and no additional
# compiler warnings are enabled, to avoid adding warnings that may not
# be supported by all compilers, or introducing build failures that
# may in fact be harmless. You may choose to enable warnings by
# uncommenting the define and adding other warnings as desired:
#
# CPPFLAGS := -Werror -Wall -Wextra -Wunused
# NO_LOAD disables the includes from Makefile.rules, they are
# included explicitly below
NO_LOAD := oemcrypto third_party
include Makefile.rules
# Include rules to build unit tests
include third_party/boringssl/ssl.target.mk
include third_party/boringssl/crypto.target.mk
include third_party/gmock.target.mk
include third_party/gtest.target.mk
include $(OEMCRYPTO_UNITTEST_DIR)/oemcrypto_unittests.target.mk
# Include rules to build the OPK libraries
include oemcrypto/odk/src/odk.target.mk
include oemcrypto/opk/build/ta.target.mk
include oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk
include oemcrypto/opk/serialization/ree/opk_ree.target.mk
include oemcrypto/opk/serialization/tee/opk_tee.target.mk
include $(WTPI_IMPL_DIR)/wtpi_impl.target.mk
# Include rules to build the WTPI test libraries
include oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/opk_ree.target.mk
include oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/opk_ree_api.target.mk
include oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_lib.target.mk
include oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/opk_tee_wtpi_test.target.mk
include oemcrypto/opk/build/wtpi_unittests.target.mk
# Add rules for the transport layer implementations for OEMCrypto TA and WTPI unit tests
include $(REE_TOS_DIR)/ree_tos.target.mk
include $(REE_TOS_WTPI_DIR)/ree_tos_wtpi.target.mk
ifeq ($(USE_TA_REFERENCE_CRYPTO),yes)
include oemcrypto/opk/oemcrypto_ta/oemcrypto_ta_reference_crypto.target.mk
ta_libs: oemcrypto_ta_reference_crypto
endif
ifeq ($(USE_TA_REFERENCE_CLOCK),yes)
include oemcrypto/opk/oemcrypto_ta/oemcrypto_ta_reference_clock.target.mk
ta_libs: oemcrypto_ta_reference_clock
endif
ifeq ($(USE_TA_REFERENCE_ROOT_OF_TRUST),yes)
include oemcrypto/opk/oemcrypto_ta/oemcrypto_ta_reference_root_of_trust.target.mk
ta_libs: oemcrypto_ta_reference_root_of_trust
endif
include oemcrypto/opk/build/liboemcrypto.target.mk

View File

@@ -0,0 +1,168 @@
# Makefile for OP-TEE liboemcrypto.so and the OP-TEE widevine trusted app
# $OPTEE must be defined as the root of the OP-TEE SDK
ifndef OPTEE
$(error OPTEE is undefined)
endif
# $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:
# Set platform-specific toolchain flags for OP-TEE
# Run make with the OPTEE_PLATFORM variable set to one of the following values:
# qemu (QEMU v7)
# stm32mp1 (STM32MP157 DK1 eval kit)
# nxpimx8m (NXP iMX8M eval kit)
# Default is QEMU
OPTEE_PLATFORM ?= qemu
CFG_TEE_TA_MALLOC_DEBUG:=y
ifeq ($(OPTEE_PLATFORM),qemu)
PLATFORM := vexpress-qemu_virt
TEEC_EXPORT ?= $(OPTEE)/out-br/build/optee_client_ext-1.0/libteec
OPTEE_TOOLCHAIN := $(OPTEE)/toolchains/aarch32
TA_DEV_KIT_DIR := $(OPTEE)/optee_os/out/arm/export-ta_arm32
CROSS_COMPILE := arm-linux-gnueabihf-
CPPFLAGS := \
-isystem $(OPTEE_TOOLCHAIN)/lib/gcc/arm-none-linux-gnueabihf/10.2.1/include \
else ifeq ($(OPTEE_PLATFORM),stm32mp1)
TEEC_EXPORT ?= $(OPTEE)/out-br/build/optee_client_ext-1.0/libteec
OPTEE_TOOLCHAIN := $(OPTEE)/toolchains/aarch32
TA_DEV_KIT_DIR := $(OPTEE)/optee_os/out/arm/export-ta_arm32
CROSS_COMPILE := arm-linux-gnueabihf-
CPPFLAGS := \
-isystem $(OPTEE_TOOLCHAIN)/lib/gcc/arm-none-linux-gnueabihf/10.2.1/include \
else ifeq ($(OPTEE_PLATFORM),nxpimx8m)
PLATFORM := imx-mx8mqevk
TEEC_EXPORT ?= $(OPTEE)/out-br/build/optee_client_ext-1.0/libteec
OPTEE_TOOLCHAIN := $(OPTEE)/toolchains/aarch64
TA_DEV_KIT_DIR := $(OPTEE)/optee_os/out/arm/export-ta_arm64
CROSS_COMPILE := aarch64-linux-gnu-
CPPFLAGS := \
-isystem $(OPTEE_TOOLCHAIN)/lib/gcc/aarch64-none-linux-gnu/10.2.1/include \
else
$(error Unknown OPTEE_PLATFORM $(OPTEE_PLATFORM))
endif
# Set paths and flags for the OP-TEE toolchain
PATH := $(PATH):$(OPTEE_TOOLCHAIN)/bin
CC_target := $(OPTEE_TOOLCHAIN)/bin/$(CROSS_COMPILE)gcc
CXX_target := $(OPTEE_TOOLCHAIN)/bin/$(CROSS_COMPILE)g++
AR_target := $(OPTEE_TOOLCHAIN)/bin/$(CROSS_COMPILE)ar
CPPFLAGS += \
-I $(OPTEE)/optee_client/public \
-Wno-psabi \
# OEMCrypto TA optional components
USE_TA_REFERENCE_CRYPTO := no
USE_TA_REFERENCE_CLOCK := no
USE_TA_REFERENCE_ROOT_OF_TRUST := no
# Where the build output goes: $CDM/out/opk_optee
builddir_name := $(shell 'pwd')/../../../out/opk_optee
$(info XXXXX builddir_name $(builddir_name))
# List libraries from the Trusted OS SDK to link into
# liboemcrypto.so
TRUSTED_OS_SDK_LIBS := $(OPTEE)/out-br/build/optee_client_ext-1.0/libteec/libteec.so
PORT_BASE_DIR:=../ports/optee
# The makefile for liboemcrypto_ta.a requires this environment variable in
# order to locate headers with configuration macros, which can be
# implementation specific
WTPI_CONFIG_MACRO_DIR := $(PORT_BASE_DIR)/ta/common/wtpi_impl
# NO_LOAD disables the includes from Makefile.rules, they are
# included explicitly from Makefile.opk instead
NO_LOAD := oemcrypto third_party
include Makefile.rules
# OP-TEE specific linker flags for liboemcrypto.so
# Manually add entire ree_tos library for liboemcrypto.so. This ree_tos library
# implementation uses a file with static functions that are not reachable by
# main, but we still want to include. So we force inclusion with --whole-archive
LIBOEMCRYPTO_LDFLAGS := \
-Wl,--whole-archive \
-L$(builddir)/ \
-lree_tos \
-Wl,-no-whole-archive \
# OP-TEE specific linker flags for the WTPI unit tests
WTPI_UNITTEST_LDFLAGS := \
-Wl,--whole-archive -lteec -L$(TEEC_EXPORT) \
-L$(builddir)/ \
-L$(builddir)/obj.target/third_party \
-L$(builddir)/obj.target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree \
-lopk_ree_api \
-lgtest \
-lwtpi_test_lib \
-lree_tos_wtpi \
-Wl,-no-whole-archive \
-static-libstdc++ \
# OP-TEE specific linker flags for the oemcrypto unit tests
OEMCRYPTO_UNITTEST_LDFLAGS := \
-static-libstdc++ \
# Makefile.opk expects this variable, which points to the directory containing
# wtpi_impl.target.mk. This builds a static lib containing all the required
# WTPI functions for the OEMCrypto TA or WTPI unit tests to link
WTPI_IMPL_DIR := $(PORT_BASE_DIR)/ta/common/wtpi_impl
# Makefile.opk expects this variable, which points to
# oemcrypto_unittests.target.mk. That makefile builds the oemcrypto unittest
# host executable.
OEMCRYPTO_UNITTEST_DIR := $(PORT_BASE_DIR)/host/oemcrypto_unittests
# Makefile.opk expects these two variables. They point to ree_tos.target.mk and
# ree_tos_wtpi.target.mk respectively, which build the transport layer
# implementations ree_tos.a and ree_tos_wtpi.a
REE_TOS_DIR := $(PORT_BASE_DIR)/host/common/tos
REE_TOS_WTPI_DIR := $(PORT_BASE_DIR)/host/common/tos
# Add rules for a simple "hello world" host executable, which can be used to check
# that REE-TEE interactions are working correctly. This is not expected by Makefile.opk.
include $(PORT_BASE_DIR)/host/oemcrypto_helloworld/oemcrypto_helloworld.target.mk
# Include common OPK make rules
include Makefile.opk
# Force ree_tos recipe to execute before liboemcrypto.so artifact is built.
# Using the absolute path in the output directory instead of the top level,
# since the absolute path is what gets built, while the top level is where
# liboemcrypto.so gets copied to
# TODO: clean up dependency organization between liboemcrypto.so and port-specific ree_tos
$(obj).target/oemcrypto/opk/build/liboemcrypto.so: ree_tos
# Add in dependency-tracking rules. $(all_deps) is the list of every single
# target in our tree. Only consider the ones with .d (dependency) info:
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
ifneq ($(d_files),)
include $(d_files)
endif
# Build the OEMCrypto trusted app using the OP-TEE target build system
# The prerequisites are linked by the oemcrypto_ta makefile, so necessarily must be built first
.PHONY: trusted_app
trusted_app: odk opk_tee oemcrypto_ta wtpi_impl
CFLAGS="$(CFLAGS.target)" $(MAKE) -C ../ports/optee/ta/oemcrypto_ta --no-builtin-variables
# Build the WTPI unit test trusted app
.PHONY: wtpi_test_ta
wtpi_test_ta: odk opk_tee_wtpi_test oemcrypto_ta wtpi_impl
CFLAGS="$(CFLAGS.target)" $(MAKE) -C ../ports/optee/ta/wtpi_test_ta --no-builtin-variables
# Add OEMCrypto TA and WTPI unit test TA recipes to all. All the other targets
# included from Makefile.opk are already part of the "all" recipe; these
# two must be added manually
.PHONY: all
all: trusted_app wtpi_test_ta

View File

@@ -0,0 +1,88 @@
{
'includes' : [
'../serialization/settings.gypi',
],
'variables': {
'platform_specific_dir': '<(DEPTH)/linux/src',
'util_dir': '<(DEPTH)/util',
'privacy_crypto_impl': 'boringssl',
'boringssl_libcrypto_path': '<(third_party_dir)/boringssl/boringssl.gyp:crypto',
'boringssl_libssl_path': '<(third_party_dir)/boringssl/boringssl.gyp:ssl',
'gtest_dependency': '<(third_party_dir)/googletest.gyp:gtest',
'gmock_dependency': '<(third_party_dir)/googletest.gyp:gmock',
'support_ota_keybox_functions': 'false',
'wtpi_test_serialization': '<(oemcrypto_ta_dir)/wtpi_test',
},
'targets' : [
{
# liboemcrypto.so shared library
'toolsets' : [ 'target' ],
'target_name': 'liboemcrypto',
'type': 'shared_library',
'link_settings': {
'libraries': [
'$(TRUSTED_OS_SDK_LIBS)',
'<(PRODUCT_DIR)/libree_tos.a',
],
},
'dependencies': [
'<(ree_dir)/ree.gyp:opk_ree',
],
'ldflags': [
'$(LIBOEMCRYPTO_LDFLAGS)',
],
},
{
# OEMCrypto unit tests
'toolsets' : [ 'target' ],
'target_name': 'oemcrypto_unittests',
'type': 'executable',
'sources': [
'<(oemcrypto_dir)/test/oemcrypto_test_main.cpp',
'<(odk_dir)/src/core_message_deserialize.cpp',
'<(odk_dir)/src/core_message_serialize.cpp',
'<(platform_specific_dir)/file_store.cpp',
'<(platform_specific_dir)/log.cpp',
'<(util_dir)/src/cdm_random.cpp',
'<(util_dir)/src/platform.cpp',
'<(util_dir)/src/rw_lock.cpp',
'<(util_dir)/src/string_conversions.cpp',
'<(util_dir)/test/test_sleep.cpp',
'<(util_dir)/test/test_clock.cpp',
],
'include_dirs': [
'<(util_dir)/include',
'<(util_dir)/test',
],
'dependencies': [
'liboemcrypto',
'<(gtest_dependency)',
'<(gmock_dependency)',
],
'includes': [
'../../test/oemcrypto_unittests.gypi'
],
'ldflags': [
'$(OEMCRYPTO_UNITTEST_LDFLAGS)',
],
},
{
# WTPI unit tests
'toolsets': [ 'target' ],
'target_name': 'wtpi_unittests',
'type': 'executable',
'sources': [
'<(wtpi_test_serialization)/wtpi_test_main.cpp',
],
'dependencies': [
'<(wtpi_test_serialization)/ree/ree_api.gyp:opk_ree_api',
'<(wtpi_test_serialization)/wtpi_test.gyp:wtpi_test_lib',
'<(gtest_dependency)',
'<(gmock_dependency)',
],
'ldflags': [
'$(WTPI_UNITTEST_LDFLAGS)',
],
},
]
}

View File

@@ -0,0 +1,30 @@
#
# Builds a static library which contains the TEE
# serialization code, dispatcher and the OEMCrypto TA
#
{
'includes' : [
'../serialization/settings.gypi',
],
'variables': {
# Path to a gyp file with a wtpi_impl target for the TA
'wtpi_impl_dir': '<(oemcrypto_dir)/opk/ports/optee/build',
},
'targets' : [
{
'target_name' : 'ta',
'toolsets' : [ 'target' ],
'type' : 'static_library',
'standalone_static_library' : 1,
'dependencies' : [
'<(odk_dir)/src/odk.gyp:odk',
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta',
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_root_of_trust',
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_clock',
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_crypto',
'<(tee_dir)/tee.gyp:opk_tee',
'<(wtpi_impl_dir)/ta.gyp:wtpi_impl',
],
},
],
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
/* Copyright 2019 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_OEMCRYPTO_API_MACROS_H_
#define OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_
#define API_MAJOR_VERSION 16
#define API_MINOR_VERSION 4
#define XSTR(s) STR(s)
#define STR(s) #s
#define BUILD_INFO() \
"Widevine OEMCrypto TA v" XSTR(API_MAJOR_VERSION) "." XSTR( \
API_MINOR_VERSION) ".0"
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */

View File

@@ -0,0 +1,111 @@
/* 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 "oemcrypto_asymmetric_key_table.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "oemcrypto_object_table.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
#if MAX_NUMBER_OF_ASYMMETRIC_KEYS <= 0
# error "MAX_NUMBER_OF_ASYMMETRIC_KEYS must be > 0"
#elif MAX_NUMBER_OF_ASYMMETRIC_KEYS >= UINT32_MAX - 1
# error "MAX_NUMBER_OF_ASYMMETRIC_KEYS is too large"
#endif
static OEMCryptoResult DtorTrampoline(void* key) {
return OPKI_FreeAsymmetricKey((AsymmetricKey*)key);
}
DEFINE_OBJECT_TABLE(key_table, AsymmetricKey, MAX_NUMBER_OF_ASYMMETRIC_KEYS,
&DtorTrampoline);
void OPKI_InitializeAsymmetricKeyTable(void) {
OPKI_UnsafeClearObjectTable(&key_table);
}
uint32_t OPKI_MaxNumberOfAsymmetricKeys(void) { return key_table.capacity; }
OEMCryptoResult OPKI_NumberOfUsedAsymmetricKeys(uint32_t* num_used_keys) {
if (num_used_keys == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*num_used_keys = OPKI_GetObjectTableUseCount(&key_table);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_CreateAsymmetricKey(
AsymmetricKey** key, AsymmetricKeyType key_type, const uint8_t* wrapped_key,
size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes) {
if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0)
return OEMCrypto_ERROR_INVALID_CONTEXT;
OEMCryptoResult result;
if (*key != NULL) {
result = OPKI_FreeAsymmetricKeyFromTable(key);
if (result != OEMCrypto_SUCCESS) return result;
}
bool key_found = false;
AsymmetricKey* cur_key = NULL;
/* If the same wrapped key already exists in the key table, just updates the
* reference counter and returns a pointer to the existing key. */
for (uint32_t i = 0; i < key_table.capacity; i++) {
cur_key = (AsymmetricKey*)OPKI_GetFromObjectTable(&key_table, i);
if (cur_key != NULL && key_type == cur_key->key_type &&
wrapped_key_length == cur_key->wrapped_key_length &&
memcmp(wrapped_key, cur_key->wrapped_key, wrapped_key_length) == 0) {
key_found = true;
break;
}
}
if (!key_found) {
cur_key = OPKI_AllocFromObjectTable(&key_table, NULL);
if (cur_key == NULL) return OEMCrypto_ERROR_TOO_MANY_KEYS;
result = OPKI_InitializeAsymmetricKey(cur_key, key_type, wrapped_key,
wrapped_key_length, key_size,
allowed_schemes);
if (result != OEMCrypto_SUCCESS) {
OPKI_FreeAsymmetricKeyFromTable(key);
return result;
}
}
cur_key->ref_count++;
*key = cur_key;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeAsymmetricKeyFromTable(AsymmetricKey** key) {
if (!key) return OEMCrypto_ERROR_INVALID_CONTEXT;
if ((*key) == NULL) return OEMCrypto_SUCCESS;
OEMCryptoResult result = OEMCrypto_SUCCESS;
if ((*key)->ref_count > 0) {
(*key)->ref_count--;
}
if ((*key)->ref_count == 0) {
result = OPKI_FreeFromObjectTable(&key_table, *key);
}
if (result == OEMCrypto_SUCCESS) *key = NULL;
return result;
}
OEMCryptoResult OPKI_TerminateAsymmetricKeyTable(void) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
for (uint32_t i = 0; i < key_table.capacity; i++) {
AsymmetricKey* key = OPKI_GetFromObjectTable(&key_table, i);
if (key) {
/* Attempt to free the key. */
key->ref_count = 0;
OEMCryptoResult free_result = OPKI_FreeAsymmetricKeyFromTable(&key);
if (free_result != OEMCrypto_SUCCESS) {
LOGE("Could not free asymmetric key at index %u with error: %u", i,
free_result);
if (result == OEMCrypto_SUCCESS) {
result = OEMCrypto_ERROR_TERMINATE_FAILED;
}
}
}
}
return result;
}

View File

@@ -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. */
#ifndef OEMCRYPTO_TA_OEMCRYPTO_ASYMMETRIC_KEY_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_ASYMMETRIC_KEY_TABLE_H_
#include "oemcrypto_key.h"
#include "wtpi_config_interface.h"
/* Initializes the key table so the session can grab keys at a late point. */
void OPKI_InitializeAsymmetricKeyTable(void);
/* Gets the max number of asymmetric keys. */
uint32_t OPKI_MaxNumberOfAsymmetricKeys(void);
/* Gets the number of currently used keys. Returns
OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not been initialized
and OEMCrypto_SUCCESS otherwise.
Caller retains ownership of |num_used_keys| and it must not be NULL. */
OEMCryptoResult OPKI_NumberOfUsedAsymmetricKeys(uint32_t* num_used_keys);
/* Grabs, gets, and initializes a AsymmetricKey. If |key| points to an existing
key, this method tries to free it before continuing. If there is an error in
generating the new key, this method will free it before returning and set
*|key| to NULL. If successful, caller gains ownership of *|key| and it must
not be NULL. */
OEMCryptoResult OPKI_CreateAsymmetricKey(
AsymmetricKey** key, AsymmetricKeyType key_type, const uint8_t* wrapped_key,
size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes);
/* Given a pointer to a AsymmetricKey*, attempts to free the AsymmetricKey it
points to if it exists, and then sets the pointer to the AsymmetricKey to
NULL. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not
been initialized, OEMCrypto_ERROR_INVALID_CONTEXT if the non-null
AsymmetricKey has not been grabbed or if its index is invalid. Returns the
result of freeing the AsymmetricKey otherwise. If there is an existing error
in the caller, in which case this is likely used for cleanup, that error will
be returned and the result of this shall be ignored. Caller retains ownership
of *|key| but **|key| will be destroyed if *|key| is not NULL. */
OEMCryptoResult OPKI_FreeAsymmetricKeyFromTable(AsymmetricKey** key);
/* Clears and cleans up the key table. The key table must be reinitialized to be
used. Returns OEMCrypto_ERROR_TERMINATE_FAILED if there are any active keys
still. Returns OEMCrypto_SUCCESS otherwise. */
OEMCryptoResult OPKI_TerminateAsymmetricKeyTable(void);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_ASYMMETRIC_KEY_TABLE_H_ */

View File

@@ -0,0 +1,37 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef OEMCRYPTO_CHECK_MACROS_H_
#define OEMCRYPTO_CHECK_MACROS_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_compiler_attributes.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
// Error-checking conditionals should almost always be done in-line in the
// function where they occur, for ease of readability and verifiability of the
// code. We made an exception for these two cases and wrote macros for them
// because they are so common that they appear multiple times in nearly every
// function.
#define RETURN_INVALID_CONTEXT_IF_NULL(parameter) \
if (UNLIKELY((parameter) == NULL)) { \
LOGE(#parameter " is NULL"); \
return OEMCrypto_ERROR_INVALID_CONTEXT; \
}
#define ABORT_IF_NULL(parameter) \
ABORT_IF(parameter == NULL, #parameter " is NULL");
#define RETURN_INVALID_CONTEXT_IF_ZERO(parameter) \
if (UNLIKELY((parameter) == 0)) { \
LOGE(#parameter " is zero"); \
return OEMCrypto_ERROR_INVALID_CONTEXT; \
}
#define ABORT_IF_ZERO(parameter) \
ABORT_IF(parameter == 0, #parameter " is zero");
#endif // OEMCRYPTO_CHECK_MACROS_H_

View File

@@ -0,0 +1,50 @@
/* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine License
Agreement. */
#ifndef OEMCRYPTO_COMPILER_ATTRIBUTES_H_
#define OEMCRYPTO_COMPILER_ATTRIBUTES_H_
#include "oemcrypto_compiler_detection.h"
/* Nonstandard attribute annotations */
#if __has_attribute(__unused__) || COMPATIBLE_WITH_GCC(2) || \
COMPATIBLE_WITH_CLANG(4)
# define UNUSED __attribute__((__unused__))
#else
# define UNUSED
#endif
#if __has_attribute(__noreturn__) || COMPATIBLE_WITH_GCC(2) || \
COMPATIBLE_WITH_CLANG(4)
# define NORETURN __attribute__((__noreturn__))
#else
# define NORETURN
#endif
#if __has_attribute(__warn_unused_result__) || COMPATIBLE_WITH_GCC(4) || \
COMPATIBLE_WITH_CLANG(4)
# define NO_IGNORE_RESULT __attribute__((__warn_unused_result__))
#else
# define NO_IGNORE_RESULT
#endif
/* Nonstandard likeliness annotations */
#if __has_builtin(__builtin_expect) || COMPATIBLE_WITH_GCC(3) || \
COMPATIBLE_WITH_CLANG(3)
# define LIKELY(x) __builtin_expect(!!(x), 1)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
#endif
/* Sanitizer annotations */
#if COMPATIBLE_WITH_CLANG(4)
# define UBSAN_IGNORE_UNSIGNED_OVERFLOW \
__attribute__((__no_sanitize__("unsigned-integer-overflow")))
#else
# define UBSAN_IGNORE_UNSIGNED_OVERFLOW
#endif
#endif /* OEMCRYPTO_COMPILER_ATTRIBUTES_H_ */

View File

@@ -0,0 +1,38 @@
/* 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_COMPILER_DETECTION_H_
#define OEMCRYPTO_COMPILER_DETECTION_H_
/* These polyfills allow us to use __has_attribute() and __has_builtin() even
on compilers that did not have them, simplifying preprocessor logic
elsewhere.
Note that __has_attribute() and __has_builtin() were often not available on
older compilers. Universal support in GCC & Clang didn't come until 2020.
Checks for attributes or builtins that are older than that should also
perform a manual compiler version check to detect older compilers. */
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#endif
#if !defined(__has_builtin)
# define __has_builtin(x) 0
#endif
#if defined(__GNUC__)
# define COMPATIBLE_WITH_GCC(major_version) (__GNUC__ >= (major_version))
#else
# define COMPATIBLE_WITH_GCC(x) 0
#endif
#if defined(__clang__) && defined(__clang_major__)
# define COMPATIBLE_WITH_CLANG(major_version) \
(__clang_major__ >= (major_version))
#else
# define COMPATIBLE_WITH_CLANG(x) 0
#endif
#endif /* OEMCRYPTO_COMPILER_DETECTION_H_ */

View File

@@ -0,0 +1,79 @@
/* 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 "oemcrypto_key.h"
#include <string.h>
#include "wtpi_abort_interface.h"
OEMCryptoResult OPKI_InitializeSymmetricKey(SymmetricKey* key,
SymmetricKeyType key_type,
KeySize key_size) {
if (key == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
key->key_handle = NULL;
memset(key->key_id, 0, KEY_ID_MAX_SIZE);
key->key_id_size = 0;
key->key_type = key_type;
key->key_size = key_size;
memset(&key->key_control_block, 0, sizeof(key->key_control_block));
key->entitled_content_key_index = 0;
key->has_entitled_content_key = false;
key->entitlement_key_index = 0;
key->is_entitled_content_key = false;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_InitializeAsymmetricKey(
AsymmetricKey* key, AsymmetricKeyType key_type, const uint8_t* wrapped_key,
size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes) {
if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (wrapped_key_length > sizeof(key->wrapped_key)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
key->key_type = key_type;
memcpy(key->wrapped_key, wrapped_key, wrapped_key_length);
key->wrapped_key_length = wrapped_key_length;
key->key_size = key_size;
key->allowed_schemes = allowed_schemes;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeSymmetricKey(SymmetricKey* key) {
if (key == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (key->key_handle != NULL) {
OEMCryptoResult result = WTPI_K1_FreeKeyHandle(key->key_handle);
if (result != OEMCrypto_SUCCESS) {
return result;
}
}
memset(key, 0, sizeof(SymmetricKey));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeAsymmetricKey(AsymmetricKey* key) {
if (key == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
memset(key, 0, sizeof(AsymmetricKey));
return OEMCrypto_SUCCESS;
}
bool OPKI_CheckKey(SymmetricKey* key, SymmetricKeyType key_type) {
return key != NULL && key->key_type == key_type;
}
bool OPKI_PrivateKeyTypeToAsymmetricKey(OEMCrypto_PrivateKeyType priv_key_type,
AsymmetricKeyType* asym_key_type) {
if (asym_key_type == NULL) return false;
switch (priv_key_type) {
case OEMCrypto_RSA_Private_Key:
*asym_key_type = DRM_RSA_PRIVATE_KEY;
return true;
case OEMCrypto_ECC_Private_Key:
*asym_key_type = DRM_ECC_PRIVATE_KEY;
return true;
}
return false;
}

View File

@@ -0,0 +1,85 @@
/* Copyright 2019 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_OEMCRYPTO_KEY_H_
#define OEMCRYPTO_TA_OEMCRYPTO_KEY_H_
#include "oemcrypto_key_control_block.h"
#include "oemcrypto_key_types.h"
#include "wtpi_config_macros.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
typedef struct SymmetricKey {
SymmetricKeyType key_type;
/* key_handle is owned by the TEE. */
WTPI_K1_SymmetricKey_Handle key_handle;
KeySize key_size;
/* For entitlement or content keys only. */
uint8_t key_id[KEY_ID_MAX_SIZE];
uint8_t key_id_size;
KeyControlBlock key_control_block;
/* Index into either the content or entitlement key table in the session. */
uint32_t session_key_index;
/* For entitlement keys only. */
uint32_t entitled_content_key_index; /* Index of entitled content key that
this entitles. */
bool has_entitled_content_key;
/* For content keys only. */
uint32_t entitlement_key_index; /* Index of entitlement key that entitles this
key. */
bool is_entitled_content_key;
OEMCryptoCipherMode cipher_mode;
} SymmetricKey;
typedef struct AsymmetricKey {
AsymmetricKeyType key_type;
uint8_t wrapped_key[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE];
size_t wrapped_key_length;
uint32_t ref_count;
/* This is the actual size of the asymmetric key in bytes when being loaded.
It is a shortcut to getting the key size without unwrapping the key first.
It is useful in cases where only the key size is needed but not the key
content. */
size_t key_size;
uint32_t allowed_schemes;
} AsymmetricKey;
/* Initializes the data fields in the |key| and sets |key|'s key_handle to
an empty handle.
Returns the result of WTPI_CreateKeyHandle if it fails and OEMCrypto_SUCCESS
otherwise.
|serialized_bytes_length| must be > 0 and |key_type| must be valid.
Caller retains ownership of all pointers and they must not be NULL. */
OEMCryptoResult OPKI_InitializeSymmetricKey(SymmetricKey* key,
SymmetricKeyType key_type,
KeySize key_size);
/* Initializes the data fields in the |key|.
Caller retains ownership of all pointers and they must not be NULL. */
OEMCryptoResult OPKI_InitializeAsymmetricKey(
AsymmetricKey* key, AsymmetricKeyType key_type, const uint8_t* wrapped_key,
size_t wrapped_key_length, size_t key_size, uint32_t allowed_schemes);
/* Frees the key handle associated with this key if it exists and then clears
the key. Returns the result of freeing the key handle.
Caller retains ownership of |key| and it must not be NULL. */
OEMCryptoResult OPKI_FreeSymmetricKey(SymmetricKey* key);
/* Clears the asymmetric *|key|.
Caller retains ownership of |key| and it must not be NULL. */
OEMCryptoResult OPKI_FreeAsymmetricKey(AsymmetricKey* key);
/* Checks to make sure that |key| isn't NULL, its key_type matches |key_type|.
*/
bool OPKI_CheckKey(SymmetricKey* key, SymmetricKeyType key_type);
/* Converts the OEMCrypto API OEMCrypto_PrivateKeyType value to the equivalent
OPK API AsymmetricKeyType value.
Returns true if the value was converted successfully, false otherwise.
Caller retains ownership of |asym_key_type| and it must not be NULL. */
bool OPKI_PrivateKeyTypeToAsymmetricKey(OEMCrypto_PrivateKeyType priv_key_type,
AsymmetricKeyType* asym_key_type);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_H_ */

View File

@@ -0,0 +1,49 @@
/* 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 "oemcrypto_key_control_block.h"
#include <string.h>
#include "odk_endian.h"
#include "wtpi_abort_interface.h"
/* This extracts 4 bytes in network byte order to a 32 bit integer in host byte
order. */
static uint32_t extract_field_from_KCB(const uint8_t* kcb, uint8_t index) {
ABORT_IF(kcb == NULL, "Key control block pointer is NULL");
ABORT_IF(index > 3, "Invalid index: %hhu", index);
const uint8_t byte_index = index * 4;
uint32_t network_order_value;
memcpy(&network_order_value, &kcb[byte_index], sizeof(network_order_value));
return oemcrypto_be32toh(network_order_value);
}
OEMCryptoResult OPKI_ParseKeyControlBlock(const uint8_t* kcb,
KeyControlBlock* out) {
if (kcb == NULL || out == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
KeyControlBlock key_control_block;
memset(&key_control_block, 0, sizeof(key_control_block));
memcpy(key_control_block.verification, kcb, 4);
key_control_block.duration = extract_field_from_KCB(kcb, 1);
key_control_block.nonce = extract_field_from_KCB(kcb, 2);
key_control_block.control_bits = extract_field_from_KCB(kcb, 3);
const char* verification = key_control_block.verification;
if (memcmp(verification, "kc16", 4) && /* add in version 16 api */
memcmp(verification, "kc15", 4) && /* add in version 15 api */
memcmp(verification, "kc14", 4) && /* add in version 14 api */
memcmp(verification, "kc13", 4) && /* add in version 13 api */
memcmp(verification, "kc12", 4) && /* add in version 12 api */
memcmp(verification, "kc11", 4) && /* add in version 11 api */
memcmp(verification, "kc10", 4) && /* add in version 10 api */
memcmp(verification, "kc09", 4) && /* add in version 9 api */
memcmp(verification, "kctl", 4)) { /* original verification */
key_control_block.valid = false;
} else {
key_control_block.valid = true;
}
*out = key_control_block;
return OEMCrypto_SUCCESS;
}

View 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 OEMCRYPTO_TA_OEMCRYPTO_KEY_CONTROL_BLOCK_H_
#define OEMCRYPTO_TA_OEMCRYPTO_KEY_CONTROL_BLOCK_H_
#include "OEMCryptoCENCCommon.h"
typedef struct KeyControlBlock {
bool valid;
char verification[4];
uint32_t duration;
uint32_t nonce;
uint32_t control_bits;
} KeyControlBlock;
/* Parses the given |kcb| into a KeyControlBlock. Caller retains ownership of
all pointers, and they must not be NULL. Returns an error if anything
occurred that prevented parsing. If parsing succeeds but verification fails,
the function still returns OEMCrypto_SUCCESS, but the KeyControlBlock is
marked as invalid. */
OEMCryptoResult OPKI_ParseKeyControlBlock(const uint8_t* kcb,
KeyControlBlock* out);
#endif // OEMCRYPTO_TA_OEMCRYPTO_KEY_CONTROL_BLOCK_H_

View File

@@ -0,0 +1,76 @@
/* 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 "oemcrypto_key_table.h"
#include <stdint.h>
#include <string.h>
#include "oemcrypto_object_table.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
#if MAX_NUMBER_OF_KEYS <= 0
# error "MAX_NUMBER_OF_KEYS must be > 0"
#elif MAX_NUMBER_OF_KEYS >= UINT32_MAX - 1
# error "MAX_NUMBER_OF_KEYS is too large"
#endif
static OEMCryptoResult DtorTrampoline(void* key) {
return OPKI_FreeSymmetricKey((SymmetricKey*)key);
}
DEFINE_OBJECT_TABLE(key_table, SymmetricKey, MAX_NUMBER_OF_KEYS,
&DtorTrampoline);
void OPKI_InitializeKeyTable(void) { OPKI_UnsafeClearObjectTable(&key_table); }
uint32_t OPKI_MaxNumberOfKeys(void) { return key_table.capacity; }
OEMCryptoResult OPKI_NumberOfUsedKeys(uint32_t* num_used_keys) {
if (num_used_keys == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*num_used_keys = OPKI_GetObjectTableUseCount(&key_table);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_CreateKey(SymmetricKey** key, SymmetricKeyType key_type,
KeySize key_size) {
if (key == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
OEMCryptoResult result;
if (*key != NULL) {
result = OPKI_FreeKeyFromTable(key);
if (result != OEMCrypto_SUCCESS) return result;
}
*key = OPKI_AllocFromObjectTable(&key_table, NULL);
if (!*key) return OEMCrypto_ERROR_TOO_MANY_KEYS;
result = OPKI_InitializeSymmetricKey(*key, key_type, key_size);
if (result != OEMCrypto_SUCCESS) {
OPKI_FreeKeyFromTable(key);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeKeyFromTable(SymmetricKey** key) {
if (!key) return OEMCrypto_ERROR_INVALID_CONTEXT;
OEMCryptoResult result = OPKI_FreeFromObjectTable(&key_table, *key);
if (result == OEMCrypto_SUCCESS) *key = NULL;
return result;
}
OEMCryptoResult OPKI_TerminateKeyTable(void) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
for (uint32_t i = 0; i < key_table.capacity; i++) {
SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, i);
if (key) {
result = OEMCrypto_ERROR_TERMINATE_FAILED;
/* Attempt to free the key. */
OEMCryptoResult free_result = OPKI_FreeKeyFromTable(&key);
if (free_result != OEMCrypto_SUCCESS) {
LOGE("Could not free key at index %u with error: %u", i, free_result);
}
}
}
return result;
}

View File

@@ -0,0 +1,48 @@
/* Copyright 2019 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_OEMCRYPTO_KEY_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_KEY_TABLE_H_
#include "oemcrypto_key.h"
#include "wtpi_config_interface.h"
/* Initializes the key table so the session can grab keys at a late point. */
void OPKI_InitializeKeyTable(void);
/* Gets the max number of keys. */
uint32_t OPKI_MaxNumberOfKeys(void);
/* Gets the number of currently used keys. Returns
OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not been initialized
and OEMCrypto_SUCCESS otherwise.
Caller retains ownership of |num_used_keys| and it must not be NULL. */
OEMCryptoResult OPKI_NumberOfUsedKeys(uint32_t* num_used_keys);
/* Grabs, gets, and initializes a SymmetricKey to an empty key handle.
If |key| points to an existing key, this method tries to free it before
continuing. If there is an error in generating the new key, this method will
free it before returning and set *|key| to NULL.
If successful, caller gains ownership of *|key| and it must not be NULL. */
OEMCryptoResult OPKI_CreateKey(SymmetricKey** key, SymmetricKeyType key_type,
KeySize key_size);
/* Given a pointer to a SymmetricKey*, attempts to free the SymmetricKey it
points to if it exists, and then sets the pointer to the SymmetricKey to
NULL. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the key table has not
been initialized, OEMCrypto_ERROR_INVALID_CONTEXT if the non-null
SymmetricKey has not been grabbed or if its index is invalid. Returns the
result of freeing the SymmetricKey otherwise. If there is an existing error
in the caller, in which case this is likely used for cleanup, that error will
be returned and the result of this shall be ignored. Caller retains ownership
of *|key| but **|key| will be destroyed if *|key| is not NULL. */
OEMCryptoResult OPKI_FreeKeyFromTable(SymmetricKey** key);
/* Clears and cleans up the key table. The key table must be reinitialized to be
used. Returns OEMCrypto_ERROR_TERMINATE_FAILED if the table has not been
initialized or if there are any active keys still. Returns OEMCrypto_SUCCESS
otherwise. */
OEMCryptoResult OPKI_TerminateKeyTable(void);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_TABLE_H_ */

View File

@@ -0,0 +1,171 @@
/* Copyright 2019 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_OEMCRYPTO_KEY_TYPES_H_
#define OEMCRYPTO_TA_OEMCRYPTO_KEY_TYPES_H_
#include "stdbool.h"
#include "stddef.h"
#include "stdint.h"
/* The type of the cryptographic key -- either AES or HMAC. Both used for
validation and identification of a key blob. Note that root of trusts are not
included in the scope of this interface. They shouldn't be represented by a
SymmetricKey. Also note that RSA and ECC keys are a separate type and are
treated separately. */
typedef enum SymmetricKeyType {
// Keys used to decrypt media content and for generic crypto operations. These
// are AES-128, only use ECB.
// TODO(b/171430591): These should use CTR/CBC instead of handling it
// ourselves.
CONTENT_KEY = (int)0x336592b0,
// The key returned from the license server used to decrypt content keys found
// in the media. This is AES-256 CBC and only used for decrypt.
ENTITLEMENT_KEY = (int)0x375af9af,
// A derived key used to verify HMAC signed responses from the server. This
// is SHA2-256 HMAC and should only be used for verify.
MAC_KEY_SERVER = (int)0xa09c9790,
// A derived key used to sign HMAC signed requests to send to the server. This
// is SHA2-256 HMAC and should only be used for sign.
MAC_KEY_CLIENT = (int)0x05f09a35,
// A derived key used to decrypt keys given from the server and to re-encrypt
// the RSA private key for storage. This is AES-128 CBC.
ENCRYPTION_KEY = (int)0x8976b781,
// A key that is only used to derive other keys. This is typically an
// AES-128-CMAC or AES-256-CMAC key, referred to as a session key in the
// OEMCrypto specification.
DERIVING_KEY = (int)0x6ebe27b7,
} SymmetricKeyType;
/* Private key type used for DRM and OEM certificates. */
typedef enum AsymmetricKeyType {
// The provisioned device private-key.
// RSA keys are used with both decryption and signing.
DRM_RSA_PRIVATE_KEY = (int)0x2e912492,
// ECC keys are used with both key exchange and signing.
DRM_ECC_PRIVATE_KEY = (int)0x539c3183,
// TODO(b/180530495): Add OEM Cert private key.
} AsymmetricKeyType;
/* The valid possible sizes of the crypto and private key. The name is the size
in bits, while the value is the size in bytes. */
typedef enum KeySize {
UNKNOWN_KEY_SIZE = 0,
KEY_SIZE_128 = 16,
KEY_SIZE_160 = 20,
KEY_SIZE_256 = 32,
KEY_SIZE_384 = 48,
KEY_SIZE_512 = 64,
KEY_SIZE_1024 = 128,
KEY_SIZE_2048 = 256,
KEY_SIZE_3072 = 384,
KEY_SIZE_4096 = 512,
} KeySize;
/* Code often needs to convert an arbitrary size to a key size. This function
provides a quick way to do the conversion if it is valid. Returns
UNKNOWN_KEY_SIZE for invalid sizes. */
static inline KeySize OPK_LengthToKeySize(size_t val) {
switch (val) {
case KEY_SIZE_128:
return KEY_SIZE_128;
case KEY_SIZE_160:
return KEY_SIZE_160;
case KEY_SIZE_256:
return KEY_SIZE_256;
case KEY_SIZE_384:
return KEY_SIZE_384;
case KEY_SIZE_512:
return KEY_SIZE_512;
case KEY_SIZE_1024:
return KEY_SIZE_1024;
case KEY_SIZE_2048:
return KEY_SIZE_2048;
case KEY_SIZE_3072:
return KEY_SIZE_3072;
case KEY_SIZE_4096:
return KEY_SIZE_4096;
default:
return UNKNOWN_KEY_SIZE;
}
}
// TODO(b/180733509): We assume this is a packed structure.
/* This is the format of a Widevine keybox. */
typedef struct WidevineKeybox { /* 128 bytes total. */
/* C character array identifying the device. Padded with NULL to fit array. */
uint8_t device_id[32];
/* 128 bit AES key assigned to device. Generated by Widevine. */
uint8_t device_key[16];
/* Key Data. Encrypted data. */
uint8_t data[72];
/* Constant code used to recognize a valid keybox "kbox" = 0x6b626f78. */
uint8_t magic[4];
/* The CRC checksum of the first 124 bytes of the keybox. */
uint8_t crc[4];
} WidevineKeybox;
/* Key Control Block Bit Masks: */
#define CONTROL_OBSERVE_DATA_PATH (1 << 31)
#define CONTROL_OBSERVE_HDCP (1 << 30)
#define CONTROL_OBSERVE_CGMS (1 << 29)
#define CONTROL_REQUIRE_ANTI_ROLLBACK_HARDWARE (1 << 28)
#define CONTROL_ALLOW_HASH_VERIFICATION (1 << 24)
#define SHARED_LICENSE (1 << 23)
#define CONTROL_SRM_VERSION_REQUIRED (1 << 22)
#define CONTROL_DISABLE_ANALOG_OUTPUT (1 << 21)
#define CONTROL_SECURITY_PATCH_LEVEL_SHIFT 15
#define CONTROL_SECURITY_PATCH_LEVEL_MASK \
(0x3F << CONTROL_SECURITY_PATCH_LEVEL_SHIFT)
#define CONTROL_REPLAY_MASK (0x03 << 13)
#define CONTROL_NONCE_REQUIRED (0x01 << 13)
#define CONTROL_NONCE_OR_ENTRY (0x02 << 13)
#define CONTROL_HDCP_VERSION_SHIFT 9
#define CONTROL_HDCP_VERSION_MASK (0x0F << CONTROL_HDCP_VERSION_SHIFT)
#define CONTROL_ALLOW_ENCRYPT (1 << 8)
#define CONTROL_ALLOW_DECRYPT (1 << 7)
#define CONTROL_ALLOW_SIGN (1 << 6)
#define CONTROL_ALLOW_VERIFY (1 << 5)
#define CONTROL_DATA_PATH_SECURE (1 << 4)
#define CONTROL_NONCE_ENABLED (1 << 3)
#define CONTROL_HDCP_REQUIRED (1 << 2)
#define CONTROL_CGMS_MASK 0x03
#define CONTROL_CGMS_COPY_FREELY 0x00
#define CONTROL_CGMS_COPY_ONCE 0x02
#define CONTROL_CGMS_COPY_NEVER 0x03
/* Various constants and sizes */
#define AES_BLOCK_SIZE 16
#define KEY_CONTROL_SIZE 16
#define KEY_ID_MAX_SIZE 16
#define KEY_IV_SIZE 16
#define KEY_PAD_SIZE 16
#define KEY_SIZE 16
#define MAC_KEY_SIZE 32
#define KEYBOX_KEY_DATA_SIZE 72
#define KEYBOX_DEVICE_ID_SIZE 32
#define SRM_REQUIREMENT_SIZE 12
#define SHA256_DIGEST_LENGTH 32
#define SHA_DIGEST_LENGTH 20
/* TODO(b/145026434): The value of PKCS8_RSA_KEY_MAX_SIZE is purely from testing
with openssl and is not derived from any specification. Generating 3072-bit
PKCS8 RSA keys gave me keys of a max size of 1794 bytes so I added a bit of
padding to make sure it's okay. This is NOT guaranteed to work for all DRM
keys. */
#define PKCS8_RSA_KEY_MAX_SIZE 2000
/* Similar to RSA key size, this is from testing with OpenSSL/BoringSSL
* serializing of a secp521r1 (largest of the supported curves) private
* key. The encoding of an ECC key is ASN.1 encoded PKCS8 PrivateKeyInfo
* containing ECPrivateKey structure defined in RFC5915. Only named curves
* are supported, limiting the size of the key message. */
#define PKCS8_ECC_KEY_MAX_SIZE 250
/* PKCS8_DRM_KEY_MAX_SIZE must be the larger of the two. */
#if PKCS8_RSA_KEY_MAX_SIZE >= PKCS8_ECC_KEY_MAX_SIZE
# define PKCS8_DRM_KEY_MAX_SIZE PKCS8_RSA_KEY_MAX_SIZE
#else
# define PKCS8_DRM_KEY_MAX_SIZE PKCS8_ECC_KEY_MAX_SIZE
#endif
#endif /* OEMCRYPTO_TA_OEMCRYPTO_KEY_TYPES_H_ */

View File

@@ -0,0 +1,16 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Primary
// License Agreement.
#ifndef OEMCRYPTO_MATH_H_
#define OEMCRYPTO_MATH_H_
#include <stdint.h>
static inline uint32_t OPK_MinU32(uint32_t a, uint32_t b) {
return (a < b) ? a : b;
}
static inline size_t OPK_MinUX(size_t a, size_t b) { return (a < b) ? a : b; }
#endif // OEMCRYPTO_MATH_H_

View File

@@ -0,0 +1,93 @@
/* 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 "oemcrypto_object_table.h"
#include "oemcrypto_check_macros.h"
#include "wtpi_logging_interface.h"
static void* UnsafeGetElem(OPKI_ObjectTable* table, uint32_t index) {
return (char*)table->elems + index * table->elem_size;
}
void* OPKI_AllocFromObjectTable(OPKI_ObjectTable* table, uint32_t* index) {
if (!table) return NULL;
if (table->next_free[0] == 0) {
// This should be impossible, so this means we aren't initialized yet (since
// the array should be filled with 0 initially).
for (uint32_t i = 0; i < table->capacity; i++) {
table->next_free[i] = i + 1;
}
}
const uint32_t new_index = table->first_free;
if (new_index == table->capacity) return NULL;
if (index) *index = new_index;
table->first_free = table->next_free[new_index];
ABORT_IF(table->is_used[new_index], "Inconsistent free list");
table->is_used[new_index] = true;
return UnsafeGetElem(table, new_index);
}
OEMCryptoResult OPKI_FreeFromObjectTable(OPKI_ObjectTable* table, void* elem) {
if (!table) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (!elem) return OEMCrypto_SUCCESS;
const intptr_t diff = (intptr_t)elem - (intptr_t)table->elems;
if (diff < 0 || diff % table->elem_size != 0) {
LOGE("Attempt to free object not in table");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const uint32_t index = (uint32_t)(diff / table->elem_size);
return OPKI_FreeFromObjectTableByIndex(table, index);
}
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(OPKI_ObjectTable* table,
uint32_t index) {
if (!table) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (index >= table->capacity) {
LOGE("Attempt to free object not in table");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!table->is_used[index]) {
LOGE("Attempt to free object that isn't being used");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (table->dtor) {
OEMCryptoResult result = table->dtor(UnsafeGetElem(table, index));
if (result != OEMCrypto_SUCCESS) return result;
}
table->next_free[index] = table->first_free;
table->first_free = index;
table->is_used[index] = false;
return OEMCrypto_SUCCESS;
}
void* OPKI_GetFromObjectTable(OPKI_ObjectTable* table, uint32_t index) {
if (!table || index >= table->capacity || !table->is_used[index]) {
return NULL;
}
return UnsafeGetElem(table, index);
}
void OPKI_UnsafeClearObjectTable(OPKI_ObjectTable* table) {
if (!table) return;
for (uint32_t i = 0; i < table->capacity; i++) {
table->next_free[i] = i + 1;
table->is_used[i] = false;
}
table->first_free = 0;
}
uint32_t OPKI_GetObjectTableUseCount(OPKI_ObjectTable* table) {
if (!table) return 0;
uint32_t ret = 0;
for (uint32_t index = 0; index < table->capacity; index++) {
if (table->is_used[index]) ret++;
}
return ret;
}

View File

@@ -0,0 +1,83 @@
/* 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_OEMCRYPTO_OBJECT_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_OBJECT_TABLE_H_
#include <stdbool.h>
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OPKI_ObjectTable {
uint32_t capacity;
size_t elem_size;
uint32_t first_free;
// Note, the argument pointer can be a pointer to any type.
OEMCryptoResult (*dtor)(void*);
void* elems;
uint32_t* next_free;
bool* is_used;
} OPKI_ObjectTable;
/**
* Defines a static table of objects of type |type_name| that will have
* |max_count| number of elements and be named |var_name|. This can optionally
* pass a destructor to call when the object is freed; this can be NULL.
*/
#define DEFINE_OBJECT_TABLE(var_name, type_name, max_count, dtor_arg) \
static type_name var_name##_elems[(max_count)]; \
/* Note these arrays are initialized to 0. */ \
static uint32_t var_name##_next_free[(max_count)]; \
static bool var_name##_is_used[(max_count)]; \
static OPKI_ObjectTable var_name = { \
.capacity = (max_count), \
.elem_size = sizeof(type_name), \
.dtor = dtor_arg, \
.first_free = 0, \
.elems = var_name##_elems, \
.next_free = var_name##_next_free, \
.is_used = var_name##_is_used, \
}
/**
* Allocates a new object from the given table. Returns NULL if there are
* no more free elements. If |index| is not null, it will be filled with the
* index of the new object.
*/
void* OPKI_AllocFromObjectTable(OPKI_ObjectTable* table, uint32_t* index);
/**
* Frees an object and makes it available for allocation. If the table was
* given a destructor, this calls it. If the destructor fails, the object is
* still allocated in the table.
*/
OEMCryptoResult OPKI_FreeFromObjectTable(OPKI_ObjectTable* table, void* elem);
/** The same as FreeFromObjectTable, but gives an index instead. */
OEMCryptoResult OPKI_FreeFromObjectTableByIndex(OPKI_ObjectTable* table,
uint32_t index);
/** Gets the object at the given index, or NULL if not valid. */
void* OPKI_GetFromObjectTable(OPKI_ObjectTable* table, uint32_t index);
/**
* Deletes all objects from the table, allowing any to be used again. This
* does NOT invoke destructors
*/
void OPKI_UnsafeClearObjectTable(OPKI_ObjectTable* table);
/** Gets the number of objects used from the given table. */
uint32_t OPKI_GetObjectTableUseCount(OPKI_ObjectTable* table);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OEMCRYPTO_TA_OEMCRYPTO_OBJECT_TABLE_H_

View File

@@ -0,0 +1,78 @@
/* 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 "oemcrypto_output.h"
#include "oemcrypto_check_macros.h"
#include "oemcrypto_overflow.h"
#include "wtpi_config_interface.h"
#include "wtpi_logging_interface.h"
OEMCryptoResult OPK_ParseDestBufferDesc(
const OEMCrypto_DestBufferDesc* incoming, OPK_OutputBuffer* outgoing,
size_t* offset) {
ABORT_IF_NULL(incoming);
ABORT_IF_NULL(outgoing);
ABORT_IF_NULL(offset);
switch (incoming->type) {
case OEMCrypto_BufferType_Clear:
if (incoming->buffer.clear.address == NULL ||
incoming->buffer.clear.address_length == 0) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
outgoing->type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
outgoing->buffer.clear_insecure = incoming->buffer.clear.address;
outgoing->size = incoming->buffer.clear.address_length;
*offset = 0;
return OEMCrypto_SUCCESS;
case OEMCrypto_BufferType_Secure:
if (incoming->buffer.secure.handle_length == 0 ||
incoming->buffer.secure.offset >=
incoming->buffer.secure.handle_length) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
outgoing->type = OPK_SECURE_OUTPUT_BUFFER;
outgoing->buffer.secure = incoming->buffer.secure.handle;
outgoing->size = incoming->buffer.secure.handle_length;
*offset = incoming->buffer.secure.offset;
return OEMCrypto_SUCCESS;
case OEMCrypto_BufferType_Direct:
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult OPK_CheckOutputBounds(const OPK_OutputBuffer* output_buffer,
size_t offset, size_t size) {
ABORT_IF_NULL(output_buffer);
ABORT_IF_ZERO(size);
ABORT_IF(!OPK_IsOutputBufferValid(output_buffer), "Invalid output buffer.");
const size_t max_allowed = WTPI_MaxOutputSizeForDecrypt();
if (max_allowed != 0 && size > max_allowed) {
return OEMCrypto_ERROR_OUTPUT_TOO_LARGE;
}
size_t total_size;
if (OPK_AddOverflowUX(size, offset, &total_size)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (total_size > output_buffer->size) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
return OEMCrypto_SUCCESS;
}
bool OPK_IsOutputBufferValid(const OPK_OutputBuffer* output_buffer) {
ABORT_IF_NULL(output_buffer);
return output_buffer->size > 0 &&
(output_buffer->type == OPK_SECURE_OUTPUT_BUFFER ||
(output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER &&
output_buffer->buffer.clear_insecure != NULL));
}

View File

@@ -0,0 +1,39 @@
/* 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_OEMCRYPTO_OUTPUT_H_
#define OEMCRYPTO_TA_OEMCRYPTO_OUTPUT_H_
#include "OEMCryptoCENC.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
/* Initializes a new OPK_OutputBuffer and offset from an incoming
OEMCrypto_DestBufferDesc or returns an error if this is impossible.
Returns OEMCrypto_ERROR_INVALID_CONTEXT if the incoming buffer is malformed.
Returns OEMCrypto_ERROR_NOT_IMPLEMENTED if the incoming buffer is of a type
not supported by OPK_OutputBuffer. Returns OEMCrypto_SUCCESS otherwise.*/
OEMCryptoResult OPK_ParseDestBufferDesc(
const OEMCrypto_DestBufferDesc* incoming, OPK_OutputBuffer* outgoing,
size_t* offset);
/* Verifies that it is safe to write |size| bytes into |output_buffer| at offset
|offset|. This function not only checks against whether the output buffer is
large enough but also whether the size violates any of this device's limits.
It also uses the porting layer to confirm that the output buffer is actually
writeable with the given offset and size.
Returns OEMCrypto_ERROR_INVALID_CONTEXT if the combined size and offset
cannot fit in a size_t or if the porting layer rejects the write. Returns
OEMCrypto_ERROR_OUTPUT_TOO_LARGE if the write would exceed one of the
system's limits. Returns OEMCrypto_ERROR_SHORT_BUFFER if there is not enough
space in the buffer. Returns OEMCrypto_SUCCESS otherwise.*/
OEMCryptoResult OPK_CheckOutputBounds(const OPK_OutputBuffer* output_buffer,
size_t offset, size_t size);
/* Verifies that a given OPK_OutputBuffer is well-formed. */
bool OPK_IsOutputBufferValid(const OPK_OutputBuffer* output_buffer);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_OUTPUT_H_ */

View File

@@ -0,0 +1,63 @@
/* 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 "oemcrypto_overflow.h"
#include "stdbool.h"
#include "stddef.h"
#include "stdint.h"
#ifndef OPK_USE_BUILTIN_OVERFLOW
bool OPK_SubOverflowIX(int a, int b, int* c) {
if (a >= b) {
if (c) {
*c = a - b;
}
return false;
}
return true;
}
bool OPK_SubOverflowU32(uint32_t a, uint32_t b, uint32_t* c) {
if (a >= b) {
if (c) {
*c = a - b;
}
return false;
}
return true;
}
bool OPK_SubOverflowU64(uint64_t a, uint64_t b, uint64_t* c) {
if (a >= b) {
if (c) {
*c = a - b;
}
return false;
}
return true;
}
bool OPK_AddOverflowUX(size_t a, size_t b, size_t* c) {
if (SIZE_MAX - a >= b) {
if (c) {
*c = a + b;
}
return false;
}
return true;
}
bool OPK_SubOverflowUX(size_t a, size_t b, size_t* c) {
if (a >= b) {
if (c) {
*c = a - b;
}
return false;
}
return true;
}
#endif

View File

@@ -0,0 +1,62 @@
/* Copyright 2019 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_OEMCRYPTO_OVERFLOW_H_
#define OEMCRYPTO_TA_OEMCRYPTO_OVERFLOW_H_
#include "stdbool.h"
#include "stddef.h"
#include "stdint.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_compiler_detection.h"
/* Defines operators that check for overflow in arithmetic.
Uses the standard GNU builtins if defined and custom overflow functions
otherwise. */
/* TODO(b/145244569): Unify this with the interface for the odk. */
#if __has_builtin(__builtin_add_overflow) || COMPATIBLE_WITH_GCC(5) || \
COMPATIBLE_WITH_CLANG(3)
# define OPK_USE_BUILTIN_OVERFLOW 1
/* The builtins are available, so wrap them and apply NO_IGNORE_RESULT. */
NO_IGNORE_RESULT static inline bool OPK_SubOverflowIX(int a, int b, int* c) {
return __builtin_sub_overflow(a, b, c);
}
NO_IGNORE_RESULT static inline bool OPK_SubOverflowU32(uint32_t a, uint32_t b,
uint32_t* c) {
return __builtin_sub_overflow(a, b, c);
}
NO_IGNORE_RESULT static inline bool OPK_SubOverflowU64(uint32_t a, uint32_t b,
uint32_t* c) {
return __builtin_sub_overflow(a, b, c);
}
NO_IGNORE_RESULT static inline bool OPK_AddOverflowUX(size_t a, size_t b,
size_t* c) {
return __builtin_add_overflow(a, b, c);
}
NO_IGNORE_RESULT static inline bool OPK_SubOverflowUX(size_t a, size_t b,
size_t* c) {
return __builtin_sub_overflow(a, b, c);
}
#else
/* The builtins are not available, so use our implementations. */
NO_IGNORE_RESULT bool OPK_SubOverflowIX(int a, int b, int* c);
NO_IGNORE_RESULT bool OPK_SubOverflowU32(uint32_t a, uint32_t b, uint32_t* c);
NO_IGNORE_RESULT bool OPK_SubOverflowU64(uint64_t a, uint64_t b, uint64_t* c);
NO_IGNORE_RESULT bool OPK_AddOverflowUX(size_t a, size_t b, size_t* c);
NO_IGNORE_RESULT bool OPK_SubOverflowUX(size_t a, size_t b, size_t* c);
#endif /* __has_builtin(__builtin_add_overflow) || COMPATIBLE_WITH_GCC(5) */
#endif /* OEMCRYPTO_TA_OEMCRYPTO_OVERFLOW_H_ */

View File

@@ -0,0 +1,98 @@
/* 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 "oemcrypto_serialized_usage_table.h"
#include "stddef.h"
#include "string.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_usage_table.h"
/* The buffer size we need to reserve for a signed header with the given number
of entries.
TODO(b/158720996): use serialization and allow variable sized headers. This
code currently uses memcpy to serialize data. That works as long as we do not
try to change message format or want to change the header size.
*/
size_t OPKI_SignedHeaderSize(int table_size UNUSED) {
return sizeof(SignedSavedUsageHeader);
}
size_t OPKI_SignedEntrySize() { return sizeof(SignedSavedUsageEntry); }
OEMCryptoResult OPKI_PackSignedUsageHeader(
uint8_t* buffer, size_t buffer_size, const SignedSavedUsageHeader* header) {
if (buffer_size < sizeof(SignedSavedUsageHeader)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, header, sizeof(SignedSavedUsageHeader));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_PackUsageHeader(uint8_t* buffer, size_t buffer_size,
const SavedUsageHeader* header) {
if (buffer_size < sizeof(SavedUsageHeader)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, header, sizeof(SavedUsageHeader));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_PackSignedUsageEntry(uint8_t* buffer, size_t buffer_size,
const SignedSavedUsageEntry* entry) {
if (buffer_size < sizeof(SignedSavedUsageEntry)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, entry, sizeof(SignedSavedUsageEntry));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_PackUsageEntry(uint8_t* buffer, size_t buffer_size,
const SavedUsageEntry* entry) {
if (buffer_size < sizeof(SavedUsageEntry)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(buffer, entry, sizeof(SavedUsageEntry));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_UnpackSignedUsageHeader(const uint8_t* buffer,
size_t buffer_size,
SignedSavedUsageHeader* header) {
if (buffer_size < sizeof(SignedSavedUsageHeader)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(header, buffer, sizeof(SignedSavedUsageHeader));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_UnpackUsageHeader(const uint8_t* buffer,
size_t buffer_size,
SavedUsageHeader* header) {
if (buffer_size < sizeof(SavedUsageHeader)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(header, buffer, sizeof(SavedUsageHeader));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_UnpackSignedUsageEntry(const uint8_t* buffer,
size_t buffer_size,
SignedSavedUsageEntry* entry) {
if (buffer_size < sizeof(SignedSavedUsageEntry)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(entry, buffer, sizeof(SignedSavedUsageEntry));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_UnpackUsageEntry(const uint8_t* buffer, size_t buffer_size,
SavedUsageEntry* entry) {
if (buffer_size < sizeof(SavedUsageEntry)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(entry, buffer, sizeof(SavedUsageEntry));
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,113 @@
/* Copyright 2020 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_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_key_types.h"
#include "wtpi_config_macros.h"
/* File types. */
#define USAGE_TABLE_HEADER 0x68656164
#define USAGE_TABLE_ENTRY 0x656e7472
#define SIGNED_USAGE_TABLE_HEADER 0x48454144
#define SIGNED_USAGE_TABLE_ENTRY 0x456e7472
#define MAX_PST_LENGTH 255
/* This can be changed to allow for newer code to load older files. */
#define CURRENT_FILE_FORMAT_VERSION 2
/* This is the usage header, as saved to the file system, before encryption. */
typedef struct SavedUsageHeader {
uint32_t file_type; /* This should always be USAGE_TABLE_HEADER */
uint32_t format_version; /* For future backwards compatibility. */
uint64_t master_generation_number;
uint32_t table_size; /* Number of entries in the table. */
/* These are the generation numbers of each entry. */
uint64_t generation_numbers[MAX_NUMBER_OF_USAGE_ENTRIES];
} SavedUsageHeader;
/* This is all of the data we wish to save as part of a usage table entry,
* before encryption. */
typedef struct SavedUsageEntry {
uint32_t file_type; /* This should always be USAGE_TABLE_ENTRY. */
uint32_t format_version; /* For future backwards compatibility. */
uint32_t index; /* Index into usage header. */
uint64_t generation_number; /* Used to prevent rollback. */
int64_t time_of_license_received; /* Time in seconds on system clock. */
int64_t time_of_first_decrypt; /* Time in seconds on system clock. */
int64_t time_of_last_decrypt; /* Time in seconds on system clock.. */
/* Status of the entry or license, as documented in OEMCrypto spec. */
enum OEMCrypto_Usage_Entry_Status status;
/* Server Mac key wrapped for this device. */
uint8_t mac_key_server[WRAPPED_MAC_KEY_SIZE];
/* Client Mac key wrapped for this device. */
uint8_t mac_key_client[WRAPPED_MAC_KEY_SIZE];
/* Provider session token for this license. */
uint8_t pst[MAX_PST_LENGTH + 1]; /* add 1 for padding. */
uint8_t pst_length;
} SavedUsageEntry;
/* TODO(b/158720996): This should be updated when we switch to using opk
* serialization. */
/* In order to encrypt the data, we'll copy it to a slightly larger buffer
* that is a whole multiple of an AES block. */
#define PADDED_HEADER_BUFFER_SIZE (16 * (1 + sizeof(SavedUsageHeader) / 16))
#define PADDED_ENTRY_BUFFER_SIZE (16 * (1 + sizeof(SavedUsageEntry) / 16))
/* This is the usage header, as saved to the file system, after encryption and
* signing. */
typedef struct SignedSavedUsageHeader {
uint32_t file_type; /* This should always be SIGNED_USAGE_TABLE_HEADER */
/* Used for future backwards compatibility. */
uint32_t format_version;
/* The size of the saved buffer. */
size_t buffer_size;
/* A SavedUsageHeader that was protected with WTPI_EncryptAndSign. */
uint8_t buffer[PADDED_HEADER_BUFFER_SIZE + ENCRYPT_AND_SIGN_EXTRA];
} SignedSavedUsageHeader;
/* This is a usage table entry, as saved to the file system, after encryption
* and signing. */
typedef struct SignedSavedUsageEntry {
uint32_t file_type; /* This should always be SIGNED_USAGE_TABLE_ENTRY */
/* Used for future backwards compatibility. */
uint32_t format_version;
/* The size of the saved buffer. */
size_t buffer_size;
/* A SavedUsageEntry that was protected with WTPI_EncryptAndSign. */
uint8_t buffer[PADDED_ENTRY_BUFFER_SIZE + ENCRYPT_AND_SIGN_EXTRA];
} SignedSavedUsageEntry;
/* TODO(b/158720996): use serialization to turn these structures into messages
* for saving. */
/* Size of a serialized SignedSavedUsageHeader with the specified table size. */
NO_IGNORE_RESULT size_t OPKI_SignedHeaderSize(int table_size);
/* Size of a serialized SignedSavedUsageEntry. */
NO_IGNORE_RESULT size_t OPKI_SignedEntrySize(void);
NO_IGNORE_RESULT OEMCryptoResult OPKI_PackSignedUsageHeader(
uint8_t* buffer, size_t buffer_size, const SignedSavedUsageHeader* header);
NO_IGNORE_RESULT OEMCryptoResult OPKI_PackUsageHeader(
uint8_t* buffer, size_t buffer_size, const SavedUsageHeader* header);
NO_IGNORE_RESULT OEMCryptoResult OPKI_PackSignedUsageEntry(
uint8_t* buffer, size_t buffer_size, const SignedSavedUsageEntry* entry);
NO_IGNORE_RESULT OEMCryptoResult OPKI_PackUsageEntry(
uint8_t* buffer, size_t buffer_size, const SavedUsageEntry* entry);
NO_IGNORE_RESULT OEMCryptoResult OPKI_UnpackSignedUsageHeader(
const uint8_t* buffer, size_t buffer_size, SignedSavedUsageHeader* header);
NO_IGNORE_RESULT OEMCryptoResult OPKI_UnpackUsageHeader(
const uint8_t* buffer, size_t buffer_size, SavedUsageHeader* header);
NO_IGNORE_RESULT OEMCryptoResult OPKI_UnpackSignedUsageEntry(
const uint8_t* buffer, size_t buffer_size, SignedSavedUsageEntry* entry);
NO_IGNORE_RESULT OEMCryptoResult OPKI_UnpackUsageEntry(const uint8_t* buffer,
size_t buffer_size,
SavedUsageEntry* entry);
#endif // OEMCRYPTO_TA_OEMCRYPTO_SERIALIZED_USAGE_TABLE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,297 @@
/* Copyright 2019 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_OEMCRYPTO_SESSION_H_
#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_
#include "OEMCryptoCENC.h"
#include "odk_structs.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_key.h"
#include "wtpi_config_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
/* The different states in which an OEMCrypto session can be in. */
typedef enum OEMCryptoSessionState {
SESSION_OPENED = (int)0xc159acf3,
SESSION_PREPARING_REQUEST = (int)0x5bf5c800,
SESSION_WAIT_FOR_PROVISIONING = (int)0xa93cc63e,
SESSION_PROVISIONED = (int)0x95a11af7,
SESSION_WAIT_FOR_LICENSE = (int)0x8cea3faa,
SESSION_LICENSE_LOADED = (int)0xb813366b,
SESSION_EXPIRED = (int)0x0c118e73,
SESSION_PLAYING = (int)0x4895dd47,
SESSION_USAGE_ENTRY_LOADED = (int)0xdc4483be,
SESSION_INACTIVE = (int)0x512e593a,
SESSION_CAST_RECEIVER = (int)0x738620df,
SESSION_INVALID = (int)0x23a27071,
SESSION_LOAD_OEM_RSA_KEY = (int)0x9d7cae94,
SESSION_LOAD_DRM_RSA_KEY = (int)0xbc17f592,
} OEMCryptoSessionState;
/* The API being executed for the current session. */
typedef enum OEMCryptoSessionAPI {
API_OPENSESSION = (int)0x45956770,
API_CLOSESESSION = (int)0xa84dc5a7,
API_GENERATENONCE = (int)0xb9f80df2,
API_GENERATERSASIGNATURE = (int)0x450c7dd0,
API_DERIVEKEYSFROMSESSIONKEY = (int)0xf29462c0,
API_LOADKEYS = (int)0x55c0291c,
API_LOADLICENSE = (int)0x3363f964,
API_REFRESHKEYS = (int)0xc3f785fe,
API_LOADENTITLEDCONTENTKEYS = (int)0x498bc417,
API_SELECTKEY = (int)0xef2e58fb,
API_DECRYPTCENC = (int)0xf5ad6301,
API_GENERICENCRYPT = (int)0x3bd1f139,
API_GENERICDECRYPT = (int)0xcfc2970a,
API_GENERICSIGN = (int)0xb721196a,
API_GENERICVERIFY = (int)0xe09fa38b,
API_SETDECRYPTHASH = (int)0x427f7e9b,
API_GETHASHERRORCODE = (int)0xde3477cc,
API_QUERYKEYCONTROL = (int)0x7ab3659c,
API_GENERATEDERIVEDKEYS = (int)0x59b1e187,
API_LOADOEMPRIVATEKEY = (int)0x90b86535,
API_PREPANDSIGN_LICENSE_REQUEST = (int)0x9e07085c,
API_PREPANDSIGN_PROVISION_REQUEST = (int)0xd6247d24,
API_PREPANDSIGN_RENEWAL_REQUEST = (int)0x7b55062c,
API_LOADPROVISIONING = (int)0xe8c746c9,
API_LOADDRMPRIVATEKEY = (int)0x573c7779,
API_CREATENEWUSAGEENTRY = (int)0x1e328c13,
API_LOADUSAGEENTRY = (int)0x219c4914,
API_UPDATEUSAGEENTRY = (int)0x4505ff72,
API_DEACTIVATEUSAGEENTRY = (int)0x3a82ec1b,
API_MOVEENTRY = (int)0xd7e8e3bd,
API_REPORTUSAGE = (int)0x5478e587,
API_LOADRENEWAL = (int)0xb096dc9a,
} OEMCryptoSessionAPI;
typedef enum CertSignatureType {
CERT_SIGNATURE_OEM = (int)0x386eebf3,
CERT_SIGNATURE_DRM = (int)0x6b4684e3,
} CertSignatureType;
typedef struct OEMCryptoSession {
OEMCrypto_SESSION session_id;
OEMCryptoSessionState state;
AsymmetricKey* drm_private_key;
SymmetricKey* mac_key_server;
SymmetricKey* mac_key_client;
SymmetricKey* encryption_key;
bool refresh_valid;
OEMCrypto_LicenseType license_type;
uint32_t current_content_key_index;
SymmetricKey* content_keys[CONTENT_KEYS_PER_SESSION];
uint32_t num_content_keys;
SymmetricKey* entitlement_keys[ENTITLEMENT_KEYS_PER_SESSION];
uint32_t num_entitlement_keys;
bool valid_srm_version;
uint64_t timer_start;
uint32_t allowed_schemes; /* For RSA signatures. */
bool decrypt_started; /* If the license has been used in this session. */
ODK_NonceValues nonce_values;
ODK_TimerLimits timer_limits;
ODK_ClockValues clock_values;
uint8_t license_request_hash[ODK_SHA256_HASH_SIZE];
/* These are used when doing full decrypt path testing. */
bool compute_hash; /* True if the current frame needs a hash. */
uint32_t current_hash; /* Running CRC hash of frame. */
uint32_t given_hash; /* True CRC hash of frame. */
uint32_t current_frame_number; /* Current frame for CRC hash. */
uint32_t bad_frame_number; /* Frame number with bad hash. */
OEMCryptoResult hash_error; /* Error code for first bad frame. */
/* If |recent_decrypt| is true, then a usage report cannot be generated
* without first updating the usage entry. It should be set to true whenever a
* key is used. */
bool recent_decrypt;
/* The bare minimum state check to double-confirm that at most one call of
* each of these function categories can be made during the lifetime of a
* session. This is also enforced by the OPK session state machine. */
bool nonce_created;
bool request_signed;
bool response_loaded;
} OEMCryptoSession;
/* Initializes session context.
Returns the result of initializing session values by ODK.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_InitializeSession(OEMCryptoSession* session, uint32_t index);
/* Cleans up a session declaration by freeing any used keys and clearing any
state so the session could be reused in a future OpenSession call.
Returns the result of freeing the keys in the session.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_TerminateSession(OEMCryptoSession* session);
/* Asserts that the session state in |session| is set to the appropriate value
that is needed to execute |api|.
Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on
success.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_CheckStatePreCall(OEMCryptoSession* session, OEMCryptoSessionAPI api);
/* Sets the session state in |session| to the appropriate state for having just
executed |api|.
Returns OEMCrypto_ERROR_UNKNOWN_FAILURE on failure, and OEMCrypto_SUCCESS on
success.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_SetStatePostCall(OEMCryptoSession* session, OEMCryptoSessionAPI api);
/* Sets the nonce values in |session| to the value of |nonce|.
Returns the result of setting nonce values by ODK, or
OEMCrypto_ERROR_INVALID_CONTEXT on failure. Caller retains ownership of
|session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_SetNonce(OEMCryptoSession* session,
uint32_t nonce);
/* Loads the test RSA key into the given session. */
OEMCryptoResult OPKI_LoadTestRSAKey(OEMCryptoSession* session);
/* Attempts to load the wrapped DRM private key |wrapped_key| into |session|'s
|drm_private_key| field. |key_type| must be valid. |allowed_schemes| is only
assigned for key types which support it.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_LoadDRMKey(OEMCryptoSession* session,
AsymmetricKeyType key_type,
const uint8_t* wrapped_key,
size_t wrapped_key_length,
size_t key_size,
uint32_t allowed_schemes);
/* Derives mac and encryption keys from the specific key. Uses AES-128-CMAC
and |mac_ and enc_key_contexts| to derive and create a mac_key_server,
mac_key_client, and encryption_key for the |session|.
Returns the result of the derivation if it fails or the result of key
creation.
All lengths must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_DeriveMacAndEncryptionKeys(
OEMCryptoSession* session, WTPI_K1_SymmetricKey_Handle master_key,
const uint8_t* mac_key_context, size_t mac_key_context_length,
const uint8_t* enc_key_context, size_t enc_key_context_length);
/* Verifies |signature| of |message| with the mac_key_server stored in
|session|. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the mac_key_server is
invalid, the result of signature calculation if it fails,
OEMCrypto_ERROR_SIGNATURE_FAILURE if the calculated and provided signatures
don't match, and OEMCrypto_SUCCESS otherwise.
|message_length| must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_VerifySignatureWithMacKeyServer(
OEMCryptoSession* session, const uint8_t* message, size_t message_length,
const uint8_t* signature);
/* Generates signature of |message| with the mac_key_client stored in
|session| and places it in |signature|. Returns
OEMCrypto_ERROR_UNKNOWN_FAILURE if the mac_key_client is invalid, the result
of signature calculation if it fails, OEMCrypto_ERROR_SHORT_BUFFER if the
provided |signature_length| < 32 bytes, and OEMCrypto_SUCCESS otherwise.
|message_length| must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_GenerateSignatureWithMacKeyClient(
OEMCryptoSession* session, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
/* Generates signature of |message| with the private key of OEM/DRM cert
specified by |signature_type|, and places it in |signature|.
Returns:
OEMCrypto_SUCCESS if the message was signed by OEM/DRM cert key.
OEMCrypto_ERROR_INVALID_RSA_KEY if the DRM key is RSA and the padding scheme
is not 0x1 (RSASSA-PSS with SHA1) or if the DRM key is otherwise invalid
OEMCrypto_ERROR_UNKNOWN_FAILURE if the result of RSA or ECC sign fails
|message_length| must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_GenerateCertSignature(
OEMCryptoSession* session, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length,
CertSignatureType signature_type);
/* Installs the key using the given data into the |session| depending on the
license_type. Decrypts the |key_data| using the encryption_key in the session
and then uses the first 128 bits of the decrypted key to decrypt
|key_control|. Returns OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if the session
cannot hold any more keys, OEMCrypto_ERROR_INVALID_CONTEXT if the key control
block is invalid, OEMCrypto_ERROR_INVALID_NONCE if nonce is required and the
provided nonce is not in the session's nonce table,
OEMCrypto_ERROR_UNKNOWN FAILURE for all other failures, and OEMCrypto_SUCCESS
otherwise.
All lengths must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_InstallKey(
OEMCryptoSession* session, const uint8_t* key_id, size_t key_id_length,
const uint8_t* key_data, size_t key_data_length, const uint8_t* key_data_iv,
const uint8_t* key_control, const uint8_t* key_control_iv);
/* Updates the mac_key_server and mac_key_client in |session|. Decrypts
|enc_mac_keys| using the encryption_key and splits them into the two mac
keys. Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if the encryption_key is not
valid and the result of creating the mac keys otherwise.
Caller retains ownership of all pointers and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_UpdateMacKeys(OEMCryptoSession* session,
const uint8_t* enc_mac_keys,
const uint8_t* mac_keys_iv);
/* Given a |session| and either a raw or encrypted |key_control|, refreshes
either the key with the matching |key_id| or all keys of the current license
type. If |key_id| or |key_control_iv| are NULL, the key control is assumed to
be unencrypted. If |key_id| is NULL, all keys of the current license type
will have their durations updated.
Returns OEMCrypto_ERROR_INVALID_CONTEXT if the key control is invalid,
OEMCrypto_ERROR_INVALID_NONCE if there's no matching nonce,
OEMCrypto_ERROR_NO_CONTENT_KEY if there is no key with the same key id,
OEMCrypto_ERROR_UNKNOWN_FAILURE for all other failures, and OEMCrypto_SUCCESS
otherwise.
Caller retains ownership of all pointers, and |session| and |key_control|
must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_RefreshKey(OEMCryptoSession* session,
const uint8_t* key_id,
size_t key_id_length,
const uint8_t* key_control,
const uint8_t* key_control_iv);
/* Checks whether the current content key selected in the |session| can be used
in the operation given by |use_type| and with the given |buffer_type|.
Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there is no valid current content
key, OEMCrypto_ERROR_INVALID_CONTEXT if |use_type| is not allowed by the
key control block or if the replay mask is set in the key control block,
OEMCrypto_DECRYPT_FAILED if the |buffer_type| is not allowed on the device,
OEMCrypto_ERROR_KEY_EXPIRED if the duration in the key control block has
passed, OEMCrypto_ERROR_INSUFFICIENT_HDCP if the HDCP requirements are not
met, OEMCrypto_ERROR_ANALOG_OUTPUT if the analog display requirements are not
met, and OEMCrypto_SUCCESS otherwise.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_CheckCurrentContentKeyUsage(OEMCryptoSession* session, uint32_t use_type,
OPK_OutputBuffer_Type buffer_type);
/* Updates clock and timer values for the first time playback or during a
continued playback. Updates usage entry status if necessary. Returns
OEMCrypto_ERROR_KEY_EXPIRED if ODK timer expires or usage entry is
deactivated, OEMCrypto_ERROR_UNKNOWN_FAILURE if the usage entry status is
invalid or if the system clock is unavailable,
OEMCrypto_ERROR_INVALID_CONTEXT if the ODK timer or clock is invalid, and
OEMCrypto_SUCCESS otherwise. Caller retains ownership of |session| and it
must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_UpdatePlaybackTimeAndUsageEntryStatus(OEMCryptoSession* session);
/* Decrypts a number of |samples_length| samples from given |samples| with the
specified |pattern| using the |session|'s current content key. Returns the
result of DecryptOneSample if failing to decrypt any sample, and
OEMCrypto_SUCCESS otherwise. Lengths must not be 0.
Caller retains ownership of all parameters and they must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_DecryptSamples(
OEMCryptoSession* session, const OEMCrypto_SampleDescription* samples,
size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern);
/* Gets the ODK nonce values for the given |session|. All parameters must not be
NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_GetNonceValues(
const OEMCryptoSession* session, ODK_NonceValues* nonce_values);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_H_ */

View File

@@ -0,0 +1,57 @@
/* 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 "oemcrypto_session_key_table.h"
#include <string.h>
#include "odk_util.h"
#include "wtpi_abort_interface.h"
NO_IGNORE_RESULT static SymmetricKey** get_key_table(
OEMCryptoSession* session, OEMCrypto_LicenseType license_type,
uint32_t* num_keys) {
if (session == NULL || num_keys == NULL) {
return NULL;
}
switch (license_type) {
case OEMCrypto_ContentLicense:
*num_keys = session->num_content_keys;
return session->content_keys;
case OEMCrypto_EntitlementLicense:
*num_keys = session->num_entitlement_keys;
return session->entitlement_keys;
}
// Execution can only reach this point if license_type was not a valid member
// of the enumeration.
return NULL;
}
SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session,
bool is_content_key, const uint8_t* key_id,
size_t key_id_length) {
if (session == NULL || key_id == NULL || key_id_length == 0) {
return NULL;
}
if (!is_content_key &&
session->license_type != OEMCrypto_EntitlementLicense) {
LOGE("Cannot get entitlement key for content license");
return NULL;
}
uint32_t num_keys;
OEMCrypto_LicenseType license_type =
is_content_key ? OEMCrypto_ContentLicense : OEMCrypto_EntitlementLicense;
SymmetricKey** key_table = get_key_table(session, license_type, &num_keys);
for (size_t i = 0; i < num_keys; i++) {
SymmetricKey* key = key_table[i];
ABORT_IF(key == NULL, "Key at index %zu is NULL", i);
if (key_id_length == key->key_id_size &&
crypto_memcmp(key->key_id, key_id, key_id_length) == 0) {
return key;
}
}
return NULL;
}

View File

@@ -0,0 +1,23 @@
/* Copyright 2019 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_OEMCRYPTO_SESSION_KEY_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_KEY_TABLE_H_
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_key.h"
#include "oemcrypto_session.h"
/* Finds the key from the key table corresponding to the given |is_content_key|
with the given |key_id| and |key_id_length|.
Returns either the key if there is a match or NULL otherwise.
|key_id_length| must be > 0 and |is_content_key| can only be false if the
session has an OEMCrypto_EntitlementLicense.
Caller retains ownership of all parameters and they must not be NULL. */
NO_IGNORE_RESULT SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session,
bool is_content_key,
const uint8_t* key_id,
size_t key_id_length);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_KEY_TABLE_H_ */

View File

@@ -0,0 +1,82 @@
/* 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 "oemcrypto_session_table.h"
#include <stdint.h>
#include <string.h>
#include "oemcrypto_key.h"
#include "oemcrypto_object_table.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
static OEMCryptoResult DtorTrampoline(void* session) {
return OPKI_TerminateSession((OEMCryptoSession*)session);
}
DEFINE_OBJECT_TABLE(session_table, OEMCryptoSession, MAX_NUMBER_OF_SESSIONS,
&DtorTrampoline);
void OPKI_InitializeSessionTable(void) {
OPKI_UnsafeClearObjectTable(&session_table);
}
uint32_t OPKI_MaxNumberOfSessions(void) { return session_table.capacity; }
OEMCryptoResult OPKI_NumberOfOpenSessions(uint32_t* num_open_sessions) {
if (num_open_sessions == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*num_open_sessions = OPKI_GetObjectTableUseCount(&session_table);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_GrabSession(uint32_t* index) {
if (index == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
OEMCryptoSession* session = OPKI_AllocFromObjectTable(&session_table, index);
if (!session) {
return OEMCrypto_ERROR_TOO_MANY_SESSIONS;
}
return OPKI_InitializeSession(session, *index);
}
OEMCryptoResult OPKI_GetSession(uint32_t index, OEMCryptoSession** session) {
if (session == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*session = OPKI_GetFromObjectTable(&session_table, index);
if (!*session) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPKI_FreeSession(uint32_t index) {
return OPKI_FreeFromObjectTableByIndex(&session_table, index);
}
OEMCryptoResult OPKI_TerminateSessionTable(void) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
for (uint32_t i = 0; i < session_table.capacity; i++) {
OEMCryptoSession* session = OPKI_GetFromObjectTable(&session_table, i);
if (session) {
result = OEMCrypto_ERROR_TERMINATE_FAILED;
/* Attempt to free the session. */
OEMCryptoResult free_result =
OPKI_FreeFromObjectTableByIndex(&session_table, i);
if (free_result != OEMCrypto_SUCCESS) {
LOGE("Could not free session %u with error: %u", i, free_result);
}
}
}
return result;
}
bool OPKI_NonceCollision(uint32_t nonce) {
for (uint32_t i = 0; i < session_table.capacity; i++) {
OEMCryptoSession* session = OPKI_GetFromObjectTable(&session_table, i);
if (session && session->nonce_values.nonce == nonce) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,56 @@
/* Copyright 2019 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_OEMCRYPTO_SESSION_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_SESSION_TABLE_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_session.h"
#include "wtpi_config_interface.h"
/* Initializes the session table for future OpenSession calls. */
void OPKI_InitializeSessionTable(void);
/* Gets the max number of sessions. */
NO_IGNORE_RESULT uint32_t OPKI_MaxNumberOfSessions(void);
/* Gets the number of open sessions. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED
if the session table has not been initialized and OEMCrypto_SUCCESS
otherwise.
Caller retains ownership of |num_open_sessions| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_NumberOfOpenSessions(uint32_t* num_open_sessions);
/* Attempts to grab an open entry in the session table and set |index| to the
entry position. Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session
table has not been initialized and OEMCrypto_ERROR_TOO_MANY_SESSIONS if there
are no sessions left to grab. Returns OEMCrypto_SUCCESS otherwise.
Caller retains ownership of |index| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_GrabSession(uint32_t* index);
/* Sets session to the session at |index| in the session table if it is free.
Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session table has not been
initialized and OEMCrypto_ERROR_INVALID_SESSION if the session has not been
grabbed or if the index is invalid. Returns OEMCrypto_SUCCESS otherwise.
Caller retains ownership of |session| and it must not be NULL. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_GetSession(uint32_t index,
OEMCryptoSession** session);
/* Given a non-free session |index|, attempts to free it so it can be reused.
Returns OEMCrypto_ERROR_SYSTEM_INVALIDATED if the session table has not been
initialized and OEMCrypto_ERROR_INVALID_SESSION if the session has not been
grabbed or if the index is invalid. Returns OEMCrypto_SUCCESS otherwise. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_FreeSession(uint32_t index);
/* Clears and cleans up the session table. The session table must be
reinitialized to be used. Returns OEMCrypto_ERROR_TERMINATE_FAILED if the
table has not been initialized or if there are any active sessions still.
Returns OEMCrypto_SUCCESS otherwise. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_TerminateSessionTable(void);
/* Verify that the nonce is not the same as any in the session table. */
NO_IGNORE_RESULT bool OPKI_NonceCollision(uint32_t nonce);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_SESSION_TABLE_H_ */

View File

@@ -0,0 +1,160 @@
# Copyright 2019 Google LLC.All Rights Reserved.This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
{
'variables': {
# Include directory that contains wtpi_config_macros.h.
'config_macros_header_dir%': 'wtpi_reference',
'wtpi_test_impl_dir': '../ports/linux/wtpi_test_impl',
# TODO(b/207176111): add test scripts to cover both reference crypto impl
'reference_crypto_impl%': 'software',
},
'target_defaults': {
# OPK is written in pure C99. ...Aside from a few places where we use
# the preprocessor to include compiler-specific features only on supporting
# compilers. ...And aside from the reference crypto porting layer, which has
# to be C11. But the core OPK code will compile on the most pure,
# pedantic C99 compiler, and to check this, we turn on flags to keep
# ourselves honest by using the maximum compiler pedantry.
'cflags': [
'-pedantic',
'-pedantic-errors',
'-Werror=pedantic',
],
'cflags_c': [
'-std=c99',
],
# To make sure no other GYP file can override our C version, we filter out
# all other langauge standards here.
'cflags_c/': [
['exclude', '-std=*'],
['include', '-std=c99'],
],
},
'targets': [
{
'target_name': 'oemcrypto_ta',
'type': 'static_library',
'standalone_static_library': 1,
'include_dirs': [
'.',
'../../include',
'wtpi',
'<(config_macros_header_dir)',
],
'sources': [
'oemcrypto.c',
'oemcrypto_asymmetric_key_table.c',
'oemcrypto_key.c',
'oemcrypto_key_control_block.c',
'oemcrypto_key_table.c',
'oemcrypto_object_table.c',
'oemcrypto_output.c',
'oemcrypto_overflow.c',
'oemcrypto_serialized_usage_table.c',
'oemcrypto_session.c',
'oemcrypto_session_key_table.c',
'oemcrypto_session_table.c',
'oemcrypto_usage_table.c',
'oemcrypto_wall_clock.c',
],
'dependencies': [
'../../odk/src/odk.gyp:odk',
],
'direct_dependent_settings': {
'include_dirs': [
'.',
'../../include',
'wtpi',
'<(config_macros_header_dir)',
],
},
},
{
'target_name': 'oemcrypto_ta_reference_root_of_trust',
'type': 'static_library',
'standalone_static_library' : 1,
'sources': [
'wtpi_reference/crypto_wrap_asymmetric.c',
'wtpi_reference/device_key.c',
'wtpi_reference/root_of_trust_layer1.c',
],
'dependencies': [
'../../odk/src/odk.gyp:odk',
'oemcrypto_ta',
],
},
{
'target_name': 'oemcrypto_ta_reference_clock',
'type': 'static_library',
'standalone_static_library' : 1,
'sources': [
'wtpi_reference/clock_and_gn_layer1.c',
],
'dependencies': [
'../../odk/src/odk.gyp:odk',
'oemcrypto_ta',
],
},
{
'target_name': 'oemcrypto_ta_reference_crypto',
'type': 'static_library',
'standalone_static_library' : 1,
'include_dirs': [
'<(config_macros_header_dir)',
'wtpi_reference',
],
# The reference implementation of the crypto interface uses
# BoringSSL/OpenSSL, which requires C11. These flags effectively do the
# opposite of the default flags, filtering out the C99 flag and
# un-filtering-out the C11 flag.
'cflags_c': [
'-std=c11',
],
'cflags_c/': [
['exclude', '-std=*'],
['include', '-std=c11'],
],
'sources': [
'wtpi_reference/crc32.c',
'wtpi_reference/crypto_asymmetric.c',
'wtpi_reference/crypto_util.c',
'wtpi_reference/decrypt_sample.c',
'wtpi_reference/ecc_util.c',
'wtpi_reference/rsa_util.c',
'<(wtpi_test_impl_dir)/device_key_access.c',
'<(wtpi_test_impl_dir)/secure_buffer_access.c',
],
'conditions': [
['reference_crypto_impl=="hardware"', {
'sources': [
'wtpi_reference/crypto_and_key_management_layer1_hw.c',
'<(wtpi_test_impl_dir)/crypto_and_key_management_layer2_hw.c',
'<(wtpi_test_impl_dir)/layer2_crypto_key_table.c',
],
}, { # else
'sources': [
'wtpi_reference/crypto_and_key_management_layer1_openssl.c',
],
}], # end else
],
'variables': {
# Needed for BoringSSL dependency build files. These SHOULD already be
# defined by a higher-level configuration, but sometimes the OPK TA
# gets included in targets that don't define them, so we define them
# again here defensively.
'privacy_crypto_impl%': 'boringssl',
'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
},
'includes': [
'../../../util/libcrypto_dependency.gypi',
],
'dependencies': [
'../../odk/src/odk.gyp:odk',
'oemcrypto_ta',
],
},
],
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
/* Copyright 2020 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_OEMCRYPTO_USAGE_TABLE_H_
#define OEMCRYPTO_TA_OEMCRYPTO_USAGE_TABLE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "OEMCryptoCENC.h"
#include "odk.h"
#include "oemcrypto_compiler_attributes.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
typedef enum UsageEntryStatus {
USAGE_ENTRY_NONE = (int)0xacbad562,
USAGE_ENTRY_NEW = (int)0x4545babc,
USAGE_ENTRY_LOADED = (int)0x766bca12,
USAGE_ENTRY_DEACTIVATED = (int)0xdacba37,
} UsageEntryStatus;
/**
* Clear out memory for the usage table. No other usage table functions may be
* called before this. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_InitializeUsageTable(void);
/**
* Erase data from usage table. No other usage table functions may be
* called without calling OPKI_InitializeUsageTable. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_TerminateUsageTable(void);
/** Gets the usage entry status of the given session. */
NO_IGNORE_RESULT UsageEntryStatus
OPKI_GetUsageEntryStatus(OEMCrypto_SESSION session_id);
/** Create a new empty usage table header. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_CreateUsageTableHeader(
uint8_t* header_buffer, size_t* header_buffer_length);
/** Load a usage table header. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length);
/**
* Create a new usage table entry and attach it to the |session|. This may
* return an error if the usage table is full, or if too many open sessions
* have active usage entries. |session| must be open and not already have an
* entry associated with it.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_CreateNewUsageEntry(
OEMCrypto_SESSION session_id, uint32_t* usage_entry_number);
/**
* Load a usage table entry and attach it to the |session|. This may return
* an error if too many open sessions have active usage entries. |session|
* must be open and not already have an entry associated with it. The
* usage_entry_number must match that in the loaded entry.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_LoadUsageEntry(
OEMCrypto_SESSION session_id, ODK_ClockValues* clock_values,
uint32_t usage_entry_number, const uint8_t* buffer, size_t buffer_length);
/**
* Release the active usage entry associated with |session|.
* Pointers must be non-null and are owned by the caller. */
void OPKI_ReleaseEntry(OEMCrypto_SESSION session_id);
/**
* Update all values in the usage entry associated with |session|. After
* updating values, the generation numbers are all updated and the master
* generation number is saved to persistent storage. Then the entry and the
* usage table header are saved to the specified buffer. If the buffer lengths
* are not large enough, none of the work above is completed -- instead the
* lengths are updated and OEMCrypto_ERROR_SHORT_BUFFER is returned.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_UpdateUsageEntry(
OEMCrypto_SESSION session_id, ODK_ClockValues* clock_values,
uint8_t* header_buffer, size_t* header_buffer_length, uint8_t* entry_buffer,
size_t* entry_buffer_length);
/**
* Set the provider session token in the usage entry associated with
* |session|. This is done when a license is first loaded.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_SetUsageEntryPST(
OEMCrypto_SESSION session_id, const uint8_t* pst, size_t pst_length);
/**
* Verify the provider session token in the usage entry associated with
* |session|. This is done when a license is reloaded to verify the license
* matches the usage entry.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_VerfiyUsageEntryPST(
OEMCrypto_SESSION session_id, const uint8_t* pst, size_t pst_length);
/**
* Set the mac keys in the usage entry associated with |session|.
* This is done when a license is first loaded.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_SetUsageEntryMacKeys(
OEMCrypto_SESSION session_id, WTPI_K1_SymmetricKey_Handle mac_key_server,
WTPI_K1_SymmetricKey_Handle mac_key_client);
/**
* Verify the mac keys in the usage entry associated with
* |session|. This is done when a license is reloaded to verify the license
* matches the usage entry.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_VerifyUsageEntryMacKeys(
OEMCrypto_SESSION session_id, WTPI_K1_SymmetricKey_Handle mac_key_server,
WTPI_K1_SymmetricKey_Handle mac_key_client);
/**
* Set the recent_decrypt flag in the usage entry associated with |session|.
* This is done when a continued playback occurs.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_SetUsageEntryRecentDecrypt(OEMCrypto_SESSION session_id);
/**
* Mark the usage entry associated with |session| as deactivated. After
* this, the license may not be used to decrypt content. Pointers must be
* non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_DeactivateUsageEntry(
OEMCrypto_SESSION session_id, ODK_ClockValues* clock_values,
const uint8_t* pst, size_t pst_length);
/**
* Generate a usage report from the entry associated with |session|.
* |mac_key_client| can be null to use the stored MAC key instead;
* otherwise, pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_ReportUsage(OEMCrypto_SESSION session_id,
WTPI_K1_SymmetricKey_Handle mac_key_client, const uint8_t* pst,
size_t pst_length, uint8_t* buffer, size_t* buffer_length);
/**
* Mark the entry associated with |session| as modified and forbid a usage
* report until the data has been saved. This is done on important events
* like first decrypt and deactivation. Pointers must be non-null and are
* owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_ForbidReportUsage(OEMCrypto_SESSION session_id);
/**
* Sign |buffer| with the client mac key in the entry associated with
* |session|. Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_SignReleaseRequest(
OEMCrypto_SESSION session_id, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
/**
* Move the usage entry associated with |session| to the new index in the
* usage table header. The generation numbers are updated as specified in
* the OEMCrypto spec. Pointers must be non-null and are owned by the
* caller. */
NO_IGNORE_RESULT OEMCryptoResult OPKI_MoveEntry(OEMCrypto_SESSION session_id,
uint32_t new_index);
/**
* Shrink the usage table to the size specified.
* Pointers must be non-null and are owned by the caller. */
NO_IGNORE_RESULT OEMCryptoResult
OPKI_ShrinkUsageTableHeader(uint32_t new_entry_count, uint8_t* header_buffer,
size_t* header_buffer_length);
#endif /* OEMCRYPTO_TA_OEMCRYPTO_USAGE_TABLE_H_ */

View File

@@ -0,0 +1,18 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Primary
// License Agreement.
#include "oemcrypto_wall_clock.h"
static uint64_t gPreviousWallClock = 0;
OEMCryptoResult OPK_SetWallClockTime(uint64_t time_in_s) {
gPreviousWallClock = time_in_s;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OPK_GetWallClockTime(uint64_t* time_in_s) {
if (!time_in_s) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
*time_in_s = gPreviousWallClock;
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,58 @@
/* 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_WALL_CLOCK_H_
#define OEMCRYPTO_TA_WALL_CLOCK_H_
#include "stdint.h"
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This is a buffer interface. It allows the transport layer to set the wall
* clock whether the TA uses it or not. It also allows the TA to try to access
* the wall clock, even if the transport layer is not providing it.
*/
/**
* Set the current wall clock time. Wall clock time is also called Unix time.
*
* The transport layer will call this function on each call from the REE to the
* TEE in order to update the wall clock.
*
* @param[in] time_in_s: current wall clock time, in seconds since the Unix
* epoch.
*
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_SUCCESS on success
*/
OEMCryptoResult OPK_SetWallClockTime(uint64_t time_in_s);
/**
* Get the most recent wall clock time. Wall clock time is also called Unix
* time.
*
* The WTPI porting layer may use this to update the trusted time when the
* hardware secure timer is not active. The porting layer may assume that this
* is usually the correct time, but that it is not secure. This function should
* not be used if the TrustedTime is based on a hardware-provided secure
* wall-clock.
*
* @param[out] time_in_s: most recent wall clock time, in seconds since the Unix
* epoch.
*
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_SUCCESS on success
*/
OEMCryptoResult OPK_GetWallClockTime(uint64_t* time_in_s);
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WALL_CLOCK_H_ */

View File

@@ -0,0 +1,37 @@
# A note to Widevine Engineers
Some of the headers in wtpi/ directory are tested by the code in wtpi_test/.
wtpi_test uses serialization/generator/scrape_interface.py to parse the WTPI
interface declarations and generate serialization APIs such as:
* OPK_Pack_SaveGenerationNumber_Request(),
* OPK_Unpack_K1_DeriveKeyFromKeyHandle_Response(),
* ...
In order for the types of the parameters of these WTPI interfaces to be
correctly determined and inserted into the auto-generated
OPK_Pack_* / OPK_Unpack_* functions, certain naming conventions have to be
followed:
* To pack a variable length buffer X with type uint8_t*, the size of the
array must be named as "X_length" or XLength".
* If an output variable length buffer doesn't have an output size specified in
the parameter list, and is supposed to have the same size as the input buffer,
then the output buffer must be named as "out_buffer".
Below is an example following the naming convention above:
```
OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length,
uint8_t* out_buffer);
```
You can find more details in scrape_interface.py for what is looked for by the
parser.
WTPI interfaces that are currently covered by wtpi_test:
* wtpi_generation_number_interface.h,
* wtpi_crypto_and_key_management_interface_layer1.h,
* wtpi_crypto_asymmetric_interface.h,
* wtpi_crc32_interface.h,
Please be cautious when updating parameter names in these interfaces. It can
potentially break the auto-generated serialization functions used by the WTPI
tests if the naming convention is not enforced.

View File

@@ -0,0 +1,65 @@
/* Copyright 2019 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_ABORT_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_ABORT_INTERFACE_H_
#include <stdbool.h>
#include "oemcrypto_compiler_attributes.h"
#include "wtpi_logging_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup abort Abort Interface
*
* Define an abort function that is called if there is an unrecoverable error.
* This function should terminate the TA immediately. This function must never
* return control-flow to the caller. If your platform has the standard `libc`
* function `abort()`, it is recommended to just call `abort()`.
*
* @{
*/
/**
* Calling this function should abort the program execution. This function is
* NOT debug-only. It should abort program execution even on release builds.
*
* Code should generally not call WTPI_Abort() directly. It should instead call
* the wrapper macros ABORT() and ABORT_IF() that enforce best practices.
*/
void WTPI_Abort(void) NORETURN;
/// @}
// The macros below are not documented as part of the WTPI package because they
// are provided by Widevine, not by partners.
/* Logs the provided error message and aborts. All parameters are passed
directly to LOGE(), so format strings may be used.
The infinite loop after the WTPI_Abort() call is there as a last-ditch safety
in case the abort function somehow returns. */
#define ABORT(...) \
do { \
LOGE(__VA_ARGS__); \
WTPI_Abort(); \
for (;;) { \
} \
} while (false);
/* This macro aborts if the first parameter evaluates to true. The remaining
parameters are passed to ABORT() for logging. Note that parameters after
the first are not evaluated unless the condition fails. */
#define ABORT_IF(expression, ...) \
if (UNLIKELY((expression))) { \
ABORT(__VA_ARGS__); \
}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_ABORT_INTERFACE_H_ */

View File

@@ -0,0 +1,75 @@
/* 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_WTPI_CLOCK_INTERFACE_LAYER1_H_
#define OEMCRYPTO_TA_WTPI_CLOCK_INTERFACE_LAYER1_H_
#include "stdint.h"
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup secure-clock Monotonic Secure Clock
* Partners implementing a porting layer may either
* 1. Implement persistent_storage_layer2.h and clock_interface_layer2.h,
* and then use the reference implementation clock_and_gn_layer1.c for the
* clock and generation interfaces. This is preferred if the hardware secure
* timer resets to 0 whenever the device is inactive.
* or
* 2. Implement both this clock_interface_layer1.h and
* generation_number_interface.h. This is preferred if the system has a
* hardware secure wall clock.
*
* @{
*/
/**
* Returns the trusted time at the time of call and modifies |time_in_s|.
*
* The trusted time should be from a clock that is at least monotonic across
* reboots, and is hardware protected while the TA is active. Ideally the
* TrustedTime is a wall-clock that is hardware protected at all times, even
* across reboots, if supported by the device.
*
* The zero time is not specified. For example, it may be seconds since initial
* boot or seconds since the epoch. It may not be seconds since current boot
* because that would not be increasing over system reboot.
*
* Caller retains ownership of all pointers.
*
* @param[out] time_in_s: pointer to trusted time, in seconds.
*
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if time_in_s is a null pointer
* @retval OEMCrypto_SUCCESS on success
*/
OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s);
/**
* Initialize the system clock.
*/
OEMCryptoResult WTPI_InitializeClock(void);
/**
* Terminate the system clock.
*/
OEMCryptoResult WTPI_TerminateClock(void);
/**
* Returns the clock type. See OEMCrypto documentation,
* https://developers.google.com/widevine/drm/client/oemcrypto/v16/odk-timers
* for the definition of insecure clock, secure timer, and secure clock.
*/
OEMCrypto_Clock_Security_Level WTPI_GetClockType(void);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CLOCK_INTERFACE_LAYER1_H_ */

View File

@@ -0,0 +1,52 @@
/* 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_WTPI_CLOCK_INTERFACE_LAYER2_H_
#define OEMCRYPTO_TA_WTPI_CLOCK_INTERFACE_LAYER2_H_
#include <stdint.h>
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup secure-timer Non-monotonic Secure Clock
*
* Partners implementing a porting layer may either
* 1. Implement persistent_storage_layer2.h and this clock_interface_layer2.h,
* and then use the reference implementation clock_and_gn_layer1.c for the
* clock and generation interfaces. This is preferred if the hardware secure
* timer resets to 0 whenever the device is inactive.
* or
* 2. Implement both clock_interface_layer1.h and
* generation_number_interface.h. This is preferred if the system has a
* hardware secure wall clock.
*
* @{
*/
/**
* Retrieves the value of the secure timer and stores it in |time_in_s|.
*
* This timer should be secure and monotonic, but we allow it to reset to
* 0 whenever the system reboots.
*
* Caller retains ownership of all pointers.
*
* @param[out] time_in_s: pointer to system time, in seconds.
*
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if time_in_s is a null pointer
* @retval OEMCrypto_SUCCESS on success
*/
OEMCryptoResult WTPI_GetSecureTimer(uint64_t* time_in_s);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CLOCK_INTERFACE_LAYER2_H_ */

View File

@@ -0,0 +1,169 @@
/* Copyright 2019 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_CONFIG_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_CONFIG_INTERFACE_H_
#include "OEMCryptoCENC.h"
#include "wtpi_config_macros.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup config Configuration and Output Control
*
* This interface covers two topics:
*
* * It gives the TA access to metadata about the device such as build info,
* resource rating tier, etc.
*
* * It allows the TA to control and query the output control mechanisms such
* as CGMS-A, HDCP, etc.
*
* @{
*/
typedef enum OPK_SecurityLevel {
OPK_SECURITY_LEVEL_1 = (int)0x28dff164,
// Level 2 is deprecated
OPK_SECURITY_LEVEL_3 = (int)0x3c4ab71e,
} SecurityLevel;
/**
* Returns the security level of this TA.
*/
SecurityLevel WTPI_GetSecurityLevel(void);
/**
* Returns the provisioning method configured for this TA.
*/
OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void);
/**
* Returns the resource rating tier associated with this device.
*/
uint32_t WTPI_GetResourceRatingTier(void);
/**
* Gets the current supported version of SRM for the device and sets the
* |srm_version|. Returns OEMCrypto_SUCCESS if it was able to be fetched,
* OEMCrypto_ERROR_INVALID_CONTEXT if |srm_version| is NULL, any
* OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise.
*
* @param[out] srm_version: pointer to SRM version.
*
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
*/
OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version);
/**
* Returns whether the device has hardware protection preventing rollback of the
* usage table.
*/
bool WTPI_IsAntiRollbackHWPresent(void);
/**
* Returns whether or not the device was able to apply the CGMS protection for
* the device. The |cgms_field| correlates to those under the Key Control Block
* description in the OEMCrypto doc. If the cgms_field is invalid, return
* OEMCrypto_ERROR_UNKNOWN_FAILURE. Even if this function is not called, the
* device should attempt best effort for CGMS.
*
* @param[in] cgms_field: CGMS control bits.
*
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
*/
OEMCryptoResult WTPI_ApplyCGMS(uint8_t cgms_field);
/**
* Returns whether CGMS is enabled for analog output for this device.
*/
bool WTPI_IsCGMS_AActive(void);
/**
* Returns whether this device is capable of supporting 2-bit CGMS-A.
*/
bool WTPI_SupportsCGMS_A(void);
/**
* Returns whether the device is capable of analog display.
*/
bool WTPI_HasAnalogDisplay(void);
/**
* Returns whether analog display is enabled for this display.
*/
bool WTPI_IsAnalogDisplayActive(void);
/**
* Returns whether the analog display is capable of being disabled. If this
* device doesn't have analog display, return false.
*/
bool WTPI_CanDisableAnalogDisplay(void);
/**
* Turn off analog display and return whether it was successful. If this device
* doesn't have analog display, return false.
*/
bool WTPI_DisableAnalogDisplay(void);
/**
* Returns the max buffer size/max subsample size in bytes allowed for
* DecryptCENC. If there is no restriction, returns 0.
*/
size_t WTPI_MaxBufferSizeForDecrypt(void);
/**
* Returns the max output size in bytes allowed for DecryptCENC and CopyBuffer.
* If there is no restriction, returns 0.
*/
size_t WTPI_MaxOutputSizeForDecrypt(void);
/**
* A closed platform can use clear buffers during decryption.
* TODO(b/145245387): define what constitutes a closed platform.
*/
bool WTPI_IsClosedPlatform(void);
/**
* Returns the current capability of the device. Look at the OEMCrypto
* integration guide for full details on what the current capability entail.
*/
OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void);
/**
* Returns the maximum HDCP capability of the device. Look at the OEMCrypto
* integration guide for full details on what the maximum capability entail.
*/
OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void);
/**
* Returns the max buffer size allowed for OEMCrypto_Generic_*.
* If there is no restriction, returns 0.
*/
size_t WTPI_MaxBufferSizeForGenericCrypto(void);
/**
* Returns the max sample size allowed for OEMCrypto_DecryptCENC.
* If there is no restriction, returns 0.
*/
size_t WTPI_MaxSampleSize(void);
/** Returns the type of certificates this device can support. See
* OEMCrypto_SupportedCertificates in the integration guide for details on
* return value.
*/
uint32_t WTPI_SupportedCertificates(void);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CONFIG_INTERFACE_H_ */

View File

@@ -0,0 +1,94 @@
/* Copyright 2019 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_CRC32_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_CRC32_INTERFACE_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_output.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup crc32 CRC32
*
* This header defines a function for performing CRC32 on a buffer, possibly a
* secure one. Most partners will want to use the Widevine-provided reference
* implementation. But if you have a hardware CRC32 implementation, it may be
* more performant, so you can implement Layer 1 yourself in that case. Also, if
* your architecture does not allow secure buffers to be read from the OEMCrypto
* TA, you will need to implement this yourself.
*
* @{
*/
/**
* Initializes the 32-bit |initial_hash| to the starting CRC-32 value.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if |initial_hash| is NULL
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[out] initial_hash: initial CRC value
*/
OEMCryptoResult WTPI_Crc32Init(uint32_t* initial_hash);
/**
* Calculates the new crc-32 value given |in_length| bytes of |in| and the
* previous CRC-32 value, |prev_crc|. Places the result in |new_crc|.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any pointers are NULL or |in_length| is 0
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] in: input buffer
* @param[in] in_length: number of bytes to process
* @param[in] prev_crc: previous CRC value to start from
* @param[out] new_crc: new CRC value after processing input
*/
OEMCryptoResult WTPI_Crc32Cont(const uint8_t* in, size_t in_length,
uint32_t prev_crc, uint32_t* new_crc);
/**
* Hashes the contents of an output buffer for the purposes of decrypt hash
* verification. Calculates the new CRC-32 value given the previous CRC-32
* value, |prev_crc|, and |in_length| bytes of the output buffer |in| starting
* at offset |in_offset|. Places the result in |new_crc|.
*
* Returns
* OEMCrypto_ERROR_NOT_IMPLEMENTED if |in| is a secure buffer and this device
* does not support secure buffers.
* OEMCrypto_ERROR_INVALID_CONTEXT if |in_length| is 0 or any of the pointers
* are NULL.
* OEMCrypto_ERROR_INVALID_CONTEXT if the buffer is secure and the handle is
* invalid.
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures.
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] in: input OutputBuffer type
* @param[in] in_offset: offset into the data buffer where the CRC operation
* should begin processing bytes
* @param[in] in_length: number of bytes to process
* @param[in] prev_crc: previous CRC hash
* @param[out] new_crc: new CRC hash after bytes have been processed
*/
OEMCryptoResult WTPI_Crc32Cont_OutputBuffer(const OPK_OutputBuffer* in,
size_t in_offset, size_t in_length,
uint32_t prev_crc,
uint32_t* new_crc);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CRC32_INTERFACE_H_ */

View File

@@ -0,0 +1,517 @@
/* 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_CRYPTO_AND_KEY_MANAGEMENT_LAYER1_H_
#define OEMCRYPTO_TA_CRYPTO_AND_KEY_MANAGEMENT_LAYER1_H_
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_key_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup crypto-key-1 Crypto and Key Management (Layer 1)
*
* This component handles loading encrypted keys, decrypting the keys, and using
* the resulting keys to perform cryptographic operations.
*
* Decrypted keys should be protected from user-space. Ideally, they should be
* protected even from a compromised TA, such as by only decrypting them inside
* a separate TA or dedicated cryptography hardware that does not allow the key
* material to be read back.
*
* Layer 1 of this component can be implemented directly. However, there are two
* reference implementations of this component that may be useful to some
* partners.
*
* * Layer 1 assumes it is possible to load every key up to the devices
* maximum supported number of keys simultaneously. However, many devices have
* hardware that only supports having a small number of keys loaded
* simultaneously. To support such hardware, there is
* `crypto\_and\_key\_management\_layer1\_hw.c`. This reference
* implementation stores keys in a large key table in memory and dynamically
* loads and unloads keys from the crypto hardwares smaller key table as
* needed.
*
* * If you dont have crypto hardware at all or if your crypto hardware is
* very weak, you may instead use an OpenSSL-based reference implementation of
* Layer 1 that does all crypto operations in software. This does come at a
* security cost, as the decrypted key material is necessarily exposed to the
* OEMCrypto TA.
*
* @{
*/
/**
* Crypto and Key Management layer 1 serves as an abstraction of the
* communication between the OEMCrypto TA and the crypto implementation. The
* underlying crypto implementation can be either software-based such as
* OpenSSL, or a hardware-backed cryptography solution.
*
* Partners implementing the Crypto and Key Management porting layer may either
* 1. Implement wtpi_crypto_and_key_management_interface_layer2.h and
* key_mapping_interface.h, and then use the reference implementation
* crypto_and_key_management_layer1_hw.c. This is preferred if there's a
* hardware-backed crypto.
* or
* 2. Implement their own wtpi_crypto_and_key_management_interface_layer1.h, or
* use the reference implementation crypto_and_key_management_layer1_openssl.c
* and implement wtpi_device_key_access_interface.h and
* wtpi_secure_buffer_access_interface.h. This is preferred if a software-based
* crypto is used.
*/
typedef struct wtpi_k1_symmetric_key_handle* WTPI_K1_SymmetricKey_Handle;
/**
* Gets the key size from |key_handle| and places the result in |size|.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle to query for size
* @param[out] size: output size value
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL, or
* |key_handle| is invalid
*/
OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle,
KeySize* size);
/**
* Decrypts |in_buffer_length| bytes of |in_buffer| using AES CBC and |iv| and
* places the result in |out_buffer|. |key_handle| is a handle to the AES key
* used for decryption and |key_length| determines the number of bytes to use
* from |key_handle|. |out_buffer| must be >= |in_buffer_length| bytes.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle to use for the decrypt operation
* @param[in] key_length: length of key in bytes
* @param[in] in_buffer: input data to decrypt
* @param[in] in_buffer_length: length of input data in bytes
* @param[in] iv: initialization vector for AES operation
* @param[out] out_buffer: output buffer for decrypted data, assumed to be the
* same size as the input data
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL,
* |key_length| is not either 16 or 32 bytes, |key_length| is greater than the
* size of the key, |in_buffer_length| is 0 or not a multiple of the AES block
* size, or |key_handle| is invalid
*/
OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_SymmetricKey_Handle key_handle,
size_t key_length,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* iv, uint8_t* out_buffer);
/**
* Encrypts |in_buffer_length| bytes of |in_buffer| using AES CBC and |iv| and
* places the result in |out_buffer|. |key_handle| is a handle to the AES key
* used for encryption. |out_buffer| must be >= |in_buffer_length| bytes.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle to use for the encrypt operation
* @param[in] in_buffer: input data to encrypt
* @param[in] in_buffer_length: length of input data in bytes
* @param[in] iv: initialization vector for AES operation
* @param[out] out_buffer: output buffer for encrypted data, assumed to be the
* same size as the input data
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL,
* |in_buffer_length| is 0 or not a multiple of the AES block size, or
* |key_handle| is invalid
*/
OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* iv, uint8_t* out_buffer);
/**
* Calculates the HMAC of |input_length| bytes of |input| using SHA1 as the
* hash function and places the result in |out_buffer|. |key_handle| is a handle
* to the key used in the derivation. |out_buffer| must be >= 20 bytes.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle for the crypto operation
* @param[in] input: input data
* @param[in] input_length: length of input data in bytes
* @param[out] out_buffer: output buffer, assumed to be >= 20 bytes
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL or
* |input_length| is 0, or |key_handle| is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key_handle,
const uint8_t* input, size_t input_length,
uint8_t* out_buffer);
/**
* Calculates the SHA256 hash of |input_length| bytes of |input|, placing
* the result in |out_buffer|. |out_buffer| must be >= 32 bytes.
*
* Caller retains ownership of all pointers.
*
* @param[in] input: input data
* @param[in] input_length: length of input data in bytes
* @param[out] out_buffer: output buffer, assumed to be >= 32 bytes
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL or
* |input_length| is 0
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length,
uint8_t* out_buffer);
/**
* Calculates the HMAC of |input_length| bytes of |input| using SHA256 as
* the hash function and places the result in |out_buffer|. |key_handle| is a
* handle to the key used in the derivation. |out_buffer| must be >= 32 bytes.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle for HMAC operation
* @param[in] input: input data
* @param[in] input_length: length of input data in bytes
* @param[out] out_buffer: output buffer, assumed to be >= 32 bytes
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL or
* |input_length| is 0, or |key_handle| is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle,
const uint8_t* input, size_t input_length,
uint8_t* out_buffer);
/**
* Verifies that the HMAC of |input_length| bytes of |input| matches
* |signature| using SHA256 as the hash function. |key_handle| is a handle to
* the key used in the derivation.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle for HMAC operation
* @param[in] input: input data
* @param[in] input_length: length of input data in bytes
* @param[in] signature: signature to compare with input data after HMAC
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL or
* |input_length| is 0, or |key_handle| is invalid
* @retval OEMCrypto_ERROR_SIGNATURE_FAILURE the signature isn't valid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* input,
size_t input_length, const uint8_t* signature);
/**
* This enum and struct form a tagged union for passing output buffers to
* functions that write to them, such as decryption. Output buffers may be
* clear, insecure buffers that are represented as direct memory pointers or
* they may be secure buffers that are represented as a platform-specific
* handle.
*/
typedef enum OPK_OutputBuffer_Type {
OPK_CLEAR_INSECURE_OUTPUT_BUFFER = 0x77e790db,
OPK_SECURE_OUTPUT_BUFFER = 0x7f3b7fc9,
} OPK_OutputBuffer_Type;
typedef struct {
/* Flag indicating whether the buffer is secure or not. */
OPK_OutputBuffer_Type type;
/* If |type| is OPK_CLEAR_INSECURE_OUTPUT_BUFFER, this is a pointer to memory
that can be written directly and should be accessed through the
|clear_insecure| member of the union.
If |type| is OPK_SECURE_OUTPUT_BUFFER, this is a platform-specific handle
to a secure buffer and should be accessed through the |secure| member of
the union. */
union {
uint8_t* clear_insecure;
void* secure;
} buffer;
/* The total size of the buffer. */
size_t size;
} OPK_OutputBuffer;
/**
* Requests that the porting layer copy some data from |in| into the output
* buffer |out|, starting at offset |output_offset| and continuing for |size|
* bytes. It is possible that the memory ranges of |in| and |out| will overlap.
* The implementation of this function must behave correctly even if they
* overlap.
*
* Caller retains ownership of all pointers.
*
* @param[in] input: input data
* @param[in] input_length: length of input data to be copied, in bytes
* @param[in] out: output buffer
* @param[in] output_offset: destination offset in output buffer
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED |out| is a secure buffer and this
* device does not support secure buffers
* @retval OEMCrypto_ERROR_INVALID_CONTEXT |input_length| is 0 or any of the
* pointer parameters are NULL
* @retval OEMCrypto_ERROR_INVALID_CONTEXT |output_offset| + |input_length| is
* greater than |out.size|
* @retval OEMCrypto_ERROR_INVALID_CONTEXT the buffer is secure and the
* handle is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_C1_CopyToOutputBuffer(const uint8_t* input,
size_t input_length,
const OPK_OutputBuffer* out,
size_t output_offset);
/**
* Generates |out_length| random bytes and places them in |out|.
*
* Caller retains ownership of all pointers.
*
* @param[out] out: output buffer
* @param[in] out_length: number of bytes of random data to be generated
*
* @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE |out_length| is too big
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
* @retval OEMCrypto_SUCCESS otherwise
*/
OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t out_length);
/**
* Initializes key management layer 1.
*
* @return OEMCrypto_SUCCESS or the result returned from the initialization of
* the layer down below, if it exists.
*/
OEMCryptoResult WTPI_K1_InitializeKeyManagement(void);
/**
* Terminates key management layer 2.
*
* @return OEMCrypto_SUCCESS or the result returned from the termination of
* the layer down below, if it exists.
*/
OEMCryptoResult WTPI_K1_TerminateKeyManagement(void);
/**
* Creates a layer 1 key handle from |size| bytes of |serialized_bytes| and the
* |key_type|, and places the result in |out_key_handle|.
*
* Caller retains ownership of all parameters.
*
* @param[in] input: input key data
* @param[in] input_length: length of input data in bytes
* @param[in] key_type: type of key
* @param[out] out_key_handle: output key handle
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL, or
* size is 0
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_CreateKeyHandle(
const uint8_t* input, size_t input_length, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle);
/**
* Creates a device specific key handle that is to be used in the specified
* context. This key should be identical across reboots, but it should *not* be
* the same on different devices. The key should be unique per-context and
* per-key-type; however, MAC_KEY_CLIENT and MAC_KEY_SERVER must be the same
* key. This key will be used to encrypt data and tie it to the current device.
* |context| is the context this key will be used in the key derivation.
* |out_key_type| the type of the key to be derived.
* |out_key_size| is the size of the key to be derived, in bytes.
* |out_key_handle| should be filled with the desired key handle.
*
* Caller retains ownership of all parameters.
*
* @param[in] context: 32-bit identifier providing context to the derivation
* step
* @param[in] out_key_type: type of key to produce
* @param[out] out_key_handle: output key handle
* @param[in] out_key_size: size of output key, in bytes
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle(
uint32_t context, SymmetricKeyType out_key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size);
/**
* Decrypts |enc_key_length| bytes of |enc_key| using AES CBC with |iv| and the
* decrypting key handle |decrypt_key_handle|, creates a layer 1 key handle from
* the decrypted key with the specified type |key_type|, and places the result
* in |out_key_handle|.
*
* Caller retains ownership of all parameters.
*
* @param[in] decrypt_key_handle: key handle for AES decryption
* @param[in] enc_key: AES-encrypted key to be decrypted and turned into
* a handle
* @param[in] enc_key_length: length of AES-encrypted input key, in bytes
* @param[in] iv: initialization vector
* @param[in] key_type: type of key to produce from the AES-encrypted input
* @param[out] out_key_handle: output key handle
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL,
* |enc_key_length| is not either 16 or 32 bytes, or |decrypt_key_handle| is
* invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key,
size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle);
/**
* Decrypts |enc_mac_keys_length| bytes of |enc_mac_keys| using AES CBC with
* |iv| and the decrypting key handle |decrypt_key_handle|, from the decrypted
* keys creates one MAC_KEY_SERVER layer 1 key handle, and one MAC_KEY_CLIENT
* layer 1 key handle, and places the result in |out_mac_key_server| and
* |out_mac_key_client|, respectively.
*
* Caller retains ownership of all parameters.
*
* @param[in] decrypt_key_handle: key handle for AES decryption
* @param[in] enc_mac_keys: AES-encrypted keys to be decrypted and turned into
* handlese
* @param[in] enc_mac_keys_length: length of AES-encrypted input, in bytes
* @param[in] iv: initialization vector
* @param[out] out_mac_key_server: output key handle for server
* @param[out] out_mac_key_client: output key handle for client
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL,
* |enc_key_length| is not 64 bytes, or |decrypt_key_handle| is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys,
size_t enc_mac_keys_length, const uint8_t* iv,
WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
WTPI_K1_SymmetricKey_Handle* out_mac_key_client);
/**
* Derives a layer 1 key handle from input |key_handle| with the specified
* context.
*
* The derivation process:
* 1. Using the input key handle |key_handle|, prepare an AES_CMAC 128-bit
* operation.
* 2. Feed |counter| into the CMAC.
* 3. Feed |context_length| bytes from |context| into the CMAC.
* 4. Prepare another AES_CMAC 128-bit operation with the same input key handle.
* 5. Feed |counter+1| into the second CMAC.
* 6. Feed |context_length| bytes from |context| into the second CMAC.
* 7. Create |out_key_handle| with the same process as
* WTPI_K1_CreateKeyHandle(), using the concatenated result of the first CMAC
* operation and the second CMAC operation as the new input key data.
*
* Caller retains ownership of all parameters.
*
* @param[in] key_handle: key handle for AES CMAC operation
* @param[in] counter: input value used for CMAC. If this function is being
* called multiple times to derive different keys from the same context, this
* counter should be incremented +2 each time.
* @param[in] context: input data for AES CMAC
* @param[in] context_length: length of context data in bytesr
* @param[in] out_key_type: desired type of output keyr
* @param[in] out_key_size: desired size of output key
* @param[out] out_key_handle: output key handle
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL,
* |context_length| is 0, or |key_handle| is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle(
WTPI_K1_SymmetricKey_Handle key_handle, uint8_t counter,
const uint8_t* context, size_t context_length,
SymmetricKeyType out_key_type, KeySize out_key_size,
WTPI_K1_SymmetricKey_Handle* out_key_handle);
/**
* Wraps the |key_handle| into a buffer that can be saved to the file system.
* The wrapping key must be device unique, and is derived with the specified
* |context|. Caller ensures that |wrapped_key_length| is equal to the wrapped
* key size specified in wtpi_config_macros.h.
*
* Caller retains ownership of all parameters.
*
* @param[in] context: 32-bit identifier to act as context
* @param[in] key_handle: key handle to be wrapped
* @param[in] key_type: type of input key
* @param[out] wrapped_key: output buffer
* @param[in] wrapped_key_length: length of output buffer
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL,
* |wrapped_key_length| is not same as the size of the key to be wrapped, or
* |key_handle| is invalid
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_WrapKey(uint32_t context,
WTPI_K1_SymmetricKey_Handle key_handle,
SymmetricKeyType key_type, uint8_t* wrapped_key,
size_t wrapped_key_length);
/**
* Unwraps and creates a layer 1 key handle from |wrapped_key_length| bytes of
* |wrapped_key| and the |key_type|, and places the result in |out_key_handle|.
* The unwrapping key must be device unique, and is derived with the specified
* |context|.
*
* Caller retains ownership of all parameters.
*
* @param[in] context: 32-bit identifier to act as context
* @param[in] wrapped_key: key to be unwrapped
* @param[in] wrapped_key_length: length of input keyy
* @param[in] key_type: type of input key
* @param[out] out_key_handle: output key handle
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL, or
* |wrapped_key_length| is not either 16 or 32 bytes
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures
*/
OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle(
uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length,
SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle);
/**
* Frees |key_handle| that was constructed from a previous call to
* WTPI_K1_CreateKeyHandle.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: key handle to be freed
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_INVALID_CONTEXT |key_handle| is invalid
*/
OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_CRYPTO_AND_KEY_MANAGEMENT_LAYER1_H_ */

View File

@@ -0,0 +1,323 @@
/* 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_WTPI_CRYPTO_AND_KEY_MANAGEMENT_INTERFACE_LAYER2_H_
#define OEMCRYPTO_TA_WTPI_CRYPTO_AND_KEY_MANAGEMENT_INTERFACE_LAYER2_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_key_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup crypto-key-2 Crypto and Key Management (Layer 2)
*
* Crypto and Key Management layer 2 defines the interfaces between the
* REFERENCE implementation of Crypto and Key Management layer 1
* (crypto_and_key_management_layer2_hw.c) and the hardware-backed cryptography.
*
* Partners implementing the Crypto and Key Management porting layer may either
* 1. Implement wtpi_crypto_and_key_management_interface_layer2.h and
* key_mapping_interface.h, and then use the reference implementation
* crypto_and_key_management_layer1_hw.c. This is preferred if there's a
* hardware-backed crypto.
* or
* 2. Implement their own wtpi_crypto_and_key_management_interface_layer1.h, or
* use the reference implementation crypto_and_key_management_layer1_openssl.c
* and implement wtpi_device_key_access_interface.h and
* wtpi_secure_buffer_access_interface.h. This is preferred if a software-based
* crypto is used.
*
* @{
*/
typedef struct wtpi_k2_symmetric_key_handle* WTPI_K2_SymmetricKey_Handle;
/**
* Returns true if |key_handle| it a valid key management layer 2 handle.
* Otherwise returns false.
*/
bool WTPI_K2_IsKeyHandleValid(WTPI_K2_SymmetricKey_Handle key_handle);
/**
* Returns true if |index| it a valid key slot in the key table of key
* management layer 2. Otherwise returns false.
*/
bool WTPI_K2_IsKeyIndexValid(uint32_t index);
/**
* Gets the key slot from |key_handle| and places the result in |index|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, or
* if |key_handle| is invalid. Otherwise returns OEMCrypto_SUCCESS.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_K2_GetKeyIndex(WTPI_K2_SymmetricKey_Handle key_handle,
uint32_t* index);
/**
* Gets the key type from |key_handle| and places the result in |type|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, or
* if |key_handle| is invalid. Otherwise returns OEMCrypto_SUCCESS.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_K2_GetKeyType(WTPI_K2_SymmetricKey_Handle key_handle,
SymmetricKeyType* type);
/**
* Gets the key size from |key_handle| and places the result in |type|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL, or
* if |key_handle| is invalid. Otherwise returns OEMCrypto_SUCCESS.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_K2_GetKeySize(WTPI_K2_SymmetricKey_Handle key_handle,
KeySize* size);
/**
* Encrypts |in_length| bytes of |in| using AES CBC and |iv| and places the
* result in |out|. |key_handle| is a handle to the AES key used for encryption.
* |out| must be >= |in_length| bytes.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL,
* |in_length| is 0 or not a multiple of the AES block size, or |key_handle| is
* invalid.
* Returns OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
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);
/**
* Decrypts |in_length| bytes of |in| using AES CBC and |iv| and places the
* result in |out|. |key_handle| is a handle to the AES key used for decryption
* and |key_length| determines the number of bytes to use from |key_handle|.
* |out| must be >= |in_length| bytes.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL,
* |key_length| is not either 16 or 32 bytes, |key_length| is greater than the
* size of the key, |in_length| is 0 or not a multiple of the AES block size, or
* |key_handle| is invalid.
* Returns OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
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);
/**
* Decrypts |in_length| bytes of |in| using AES CTR and |iv| and places the
* result in |out|. |key_handle| is a handle to the AES key used for decryption.
* |out| must be >= |in_length| bytes.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL,
* |key_length| is not either 16 or 32 bytes, |key_length| is greater than the
* size of the key, |in_length| is 0 or not a multiple of the AES block size, or
* |key_handle| is invalid.
* Returns OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
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);
/**
* Calculates the HMAC of |message_length| bytes of |message| using SHA1 as the
* hash function and places the result in |out|. |key_handle| is a handle to the
* key used in the derivation.
* |out| must be >= 20 bytes.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or
* |message_length| is 0, or |key_handle| is invalid.
* Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_C2_HMAC_SHA1(WTPI_K2_SymmetricKey_Handle key_handle,
const uint8_t* message, size_t message_length,
uint8_t* out);
/**
* Calculates the HMAC of |message_length| bytes of |message| using SHA256 as
* the hash function and places the result in |out|. |key_handle| is a handle to
* the key used in the derivation.
* |out| must be >= 32 bytes.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or
* |message_length| is 0, or |key_handle| is invalid.
* Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_C2_HMAC_SHA256(WTPI_K2_SymmetricKey_Handle key_handle,
const uint8_t* message,
size_t message_length, uint8_t* out);
/**
* Verifies that the HMAC of |message_length| bytes of |message| matches
* |signature| using SHA256 as the hash function. |key_handle| is a handle to
* the key used in the derivation.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or
* |message_length| is 0, or |key_handle| is invalid.
* Returns OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature isn't valid,
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_C2_HMAC_SHA256_Verify(
WTPI_K2_SymmetricKey_Handle key_handle, const uint8_t* message,
size_t message_length, const uint8_t* signature);
/**
* Initializes key management layer 2.
*/
OEMCryptoResult WTPI_K2_InitializeKeyManagement(void);
/**
* Terminates key management layer 2.
*/
OEMCryptoResult WTPI_K2_TerminateKeyManagement(void);
/**
* Creates a layer 2 key handle from |size| bytes of |serialized_bytes| and the
* |key_type|, and places the result in |out_key_handle|. Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL, or size is
* 0, OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
OEMCryptoResult WTPI_K2_CreateKeyHandle(
const uint8_t* serialized_bytes, size_t size, SymmetricKeyType key_type,
WTPI_K2_SymmetricKey_Handle* out_key_handle);
/**
* Creates a device specific key handle that is to be used in the specified
* context. This key should be identical across reboots, but it should *not* be
* the same on different devices. The key should be unique per-context and
* per-key-type; however, MAC_KEY_CLIENT and MAC_KEY_SERVER must be the same
* key. This key will be used to encrypt data and tie it to the current device.
* |context| is the context this key will be used in the key derivation.
* |out_key_type| the type of the key to be derived.
* |out_key_size| is the size of the key to be derived, in bytes.
* |out_key_handle| should be filled with the desired key handle.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL,
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
OEMCryptoResult WTPI_K2_DeriveDeviceKeyIntoHandle(
uint32_t context, SymmetricKeyType out_key_type,
WTPI_K2_SymmetricKey_Handle* out_key_handle, KeySize out_key_size);
/**
* Decrypts |enc_key_length| bytes of |enc_key| using AES CBC with |iv| and the
* decrypting key handle |decrypt_key_handle|, creates a layer 2 key handle from
* the decrypted key with the specified type |key_type|, and places the result
* in |out_key_handle|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL,
* |enc_key_length| is not either 16 or 32 bytes, or |decrypt_key_handle| is
* invalid. Return OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other
* failures, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
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);
/**
* Decrypts |enc_mac_keys_length| bytes of |enc_mac_keys| using AES CBC with
* |iv| and the decrypting key handle |decrypt_key_handle|, from the decrypted
* keys creates one MAC_KEY_SERVER layer 2 key handle, and one MAC_KEY_CLIENT
* layer 2 key handle, and places the result in |out_mac_key_server| and
* |out_mac_key_client|, respectively.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL,
* |enc_key_length| is not 64 bytes, or |decrypt_key_handle| is invalid. Return
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
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);
/**
* Derives a key handle from input |key_handle| with the specified
* context.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL,
* |context_length| is 0, or |key_handle| is invalid.
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
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);
/**
* Wraps the |key_handle| into a buffer that can be saved to the file system.
* The wrapping key must be device unique, and is derived with the specified
* |context|. Caller ensures that |wrapped_key_length| is equal to the wrapped
* key size specified in wtpi_config_macros.h.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL,
* |wrapped_key_length| is not same as the size of the key to be wrapped, or
* |key_handle| is invalid. OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any
* other failures, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
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);
/**
* Unwraps and creates a layer 2 key handle from |wrapped_key_length| bytes of
* |wrapped_key| and the |key_type|, and places the result in |out_key_handle|.
* The unwrapping key must be device unique, and is derived with the specified
* |context|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL, or
* |wrapped_key_length| is not either 16 or 32 bytes.
* Returns OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures, and
* OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
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);
/**
* Encrypts the layer 2 |key_handle| with |encrypt_key_handle| and |iv|, into a
* buffer |out| that can be saved in the layer 1 key table.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL, or
* |key_handle| is invalid. OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any
* other failures, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
// TODO(b/158766099): This can be removed once we finish the implementation of
// WTPI_K2_WrapKey()
OEMCryptoResult WTPI_K2_EncryptKeyHandle(
WTPI_K2_SymmetricKey_Handle key_handle,
WTPI_K2_SymmetricKey_Handle encrypt_key_handle, const uint8_t* iv,
uint8_t* out);
/**
* Frees |key_handle| that was constructed from a previous call to
* WTPI_K2_CreateKeyHandle. Returns OEMCrypto_ERROR_INVALID_CONTEXT if
* |key_handle| is invalid, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_K2_FreeKeyHandle(WTPI_K2_SymmetricKey_Handle key_handle);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CRYPTO_AND_KEY_MANAGEMENT_INTERFACE_LAYER2_H_ */

View File

@@ -0,0 +1,281 @@
/* 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_WTPI_CRYPTO_ASYMMETRIC_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_CRYPTO_ASYMMETRIC_INTERFACE_H_
#include "OEMCryptoCENC.h"
#include "oemcrypto_key_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup asymmetric-crypto Asymmetric Cryptography
*
* This component handles loading decrypted asymmetric keys, using the keys to
* perform cryptographic operations, and wrapping the keys before saving to
* persistent storage.
*
* @{
*/
/**
* Forward declaration of a pointer to an implementation-specific struct holding
* all asymmetric key information.
*/
typedef struct tee_asymmetric_key_handle* WTPI_AsymmetricKey_Handle;
/**
* Creates a key handle from |input_length| bytes of |input| and the
* |key_type|, and places the result in |key_handle|.
*
* If the key type is DRM_RSA_PRIVATE_KEY, then |input| must be a DER-encoded
* PKCS8 RSA private key.
*
* If the key type is DRM_ECC_PRIVATE_KEY, then |input| must be a DER-encoded
* PKCS8 ECPrivateKey.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL or
* |input_length| is 0.
* OEMCrypto_ERROR_INVALID_RSA_KEY if |serialized_bytes| does not point
* to a valid private key of the specified |key_type| (ECC keys also return
* this error code TODO(b/201581141): Update with generic code).
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures/
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all parameters.
*
* @param[in] input: DER-encoded PKCS8 private key byte array
* @param[in] input_length: length of the input data
* @param[in] key_type: type of asymmetric key
* @param[out] key_handle: output key handle
*/
OEMCryptoResult WTPI_CreateAsymmetricKeyHandle(
const uint8_t* input, size_t input_length, AsymmetricKeyType key_type,
WTPI_AsymmetricKey_Handle* key_handle);
/**
* Creates a key handle from |input_length| bytes of |input| and the
* |key_type|, and places the result in |key_handle|.
*
* |*allowed_schemes| should be filled with the padding schemes that can be used
* with the key.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL or
* |input_length| is 0.
* OEMCrypto_ERROR_INVALID_RSA_KEY if |key_type| is DRM_PRIVATE_RSA_KEY
* and |serialized_bytes| is an invalid PKCS8 RSA private key; or if |key_type|
* DRM_ECC_PRIVATE_KEY and |serialized_bytes| is not a valid ECPrivateKey.
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures.
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all parameters.
*
* @param[in] input:
* @param[in] input_length:
* @param[in] key_type:
* @param[out] key_handle:
* @param[out] allowed_schemes:
*/
OEMCryptoResult WTPI_UnwrapIntoAsymmetricKeyHandle(
const uint8_t* input, size_t input_length, AsymmetricKeyType key_type,
WTPI_AsymmetricKey_Handle* key_handle, uint32_t* allowed_schemes);
/**
* Frees |key_handle| that was constructed from a previous call to
* WTPI_CreateAsymmetricKeyHandle.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if |key_handle| is NULL.
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures.
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] key_handle: previously allocated key handle
*/
OEMCryptoResult WTPI_FreeAsymmetricKeyHandle(
WTPI_AsymmetricKey_Handle key_handle);
/**
* Calculates the buffer size needed to wrap the given private key. This is
* given the number of bytes in the encrypted private key.
*
* @param[in] enc_private_key_length: length of encrypted private key to be
* wrapped
* @param[in] key_type: type of asymmetric key
* @param[out] buffer_size: output result with required wrapping size
*/
OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(size_t enc_private_key_length,
AsymmetricKeyType key_type,
size_t* buffer_size);
/**
* Wraps the key data into a buffer that can be saved to the file system. The
* wrapping must be device unique.
*
* Caller retains ownership of |clear_key| and |output| and they must
* not be NULL. Caller ensures that size is at least as big as the wrapped key
* size specified in WTPI_GetWrappedAsymmetricKeySize.
*
* This is given the clear, PKCS8-padded key and the key may be prefixed with
* "SIGN" and a 4-byte code for the padding schemes.
*
* @param[out] output: destination buffer that will contain the wrapped key data
* @param[out] output_length: length of destination buffer
* @param[in] key_type: type of asymmetric key
* @param[in] clear_key: DER-encoded PKCS8 RSA private key data with 8 bytes of
* prefix data or PKCS8 ECPrivateKey (no prefix data).
* @param[in] clear_key_length: length of input data
*/
// TODO(b/185149406): Consider using WTPI_AsymmetricKey_Handle instead to avoid
// passing clear keys around.
OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length,
AsymmetricKeyType key_type,
const uint8_t* clear_key,
size_t clear_key_length);
/**
* Sign |message_length| bytes of |message| with the given RSA key handle using
* the given |padding scheme| and place the result in |signature|.
* |key| is a handle to the RSA key used for signing.
*
* Returns
* OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if
* |signature| is NULL, in which case it sets |signature_length| to the
* appropriate length.
* OEMCrypto_ERROR_INVALID_CONTEXT if |message_length| is 0 or if any of the
* pointers except |signature| are NULL,
* OEMCrypto_ERROR_INVALID_RSA_KEY if the padding_scheme provided is not
* supported,
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures,
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] key: handle with RSA key required to sign
* @param[in] message: input data to be signed
* @param[in] message_length: length of data to be signed
* @param[out] signature: destination buffer for output signature
* @param[in,out] signature_length: size of destination buffer
* @param[in] padding_scheme: RSA padding scheme used for signing
*/
OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
/**
* Decrypts |input_length| bytes of |input| and places it in |out|. The padding
* scheme shall only be PKCS1 OAEP. |key| is a handle to the RSA key used for
* decryption.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or
* |input_length| is 0,
* OEMCrypto_ERROR_SHORT_BUFFER if |out_length| is too small, in which case it
* sets |out_length| to the appropriate length,
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures,
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] key: handle with RSA key required to decrypt
* @param[in] input: input data to be decrypted
* @param[in] input_length: length of data to be decrypted
* @param[out] out: destination buffer for decrypted data
* @param[in,out] out_length: size of destination buffer
*/
OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key,
const uint8_t* input, size_t input_length,
uint8_t* out, size_t* out_length);
/**
* Sign |message_length| bytes of |message| with the given ECC key handle using
* the ECDSA with a curve specific hashing algorithm and place the result in
* |signature|. |key| is a handle to the ECC key used for signing.
*
* Returns
* OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small or if
* |signature| is NULL, in which case it sets |signature_length| to the
* appropriate length.
* OEMCrypto_ERROR_INVALID_CONTEXT if |message_length| is 0 or if any of
* the pointers except |signature| are NULL.
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures.
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] key: handle with ECC key, required for signing.
* @param[in] message: input data to be signed
* @param[in] message_length: length of input data in bytes
* @param[out] signature: destination buffer for signature
* @param[in,out] signature_length: size of |signature| buffer, may be
* modified based on used/required space of output.
*/
OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
/**
* Derives the ECC-based session key using Widevine ECDH. The derived
* key is placed into |session_key|. This key is a AES-256 to be used
* as the key in the CMAC function used in the MAC and ENC key session
* processes.
*
* Returns
* OEMCrypto_ERROR_SHORT_BUFFER if |session_key_length| is too small or
* if |session_key| is NULL, in which case it sets |session_key_length|
* to the appropriate length.
* OEMCrypto_ERROR_INVALID_CONTEXT if |key_source_length| is 0 or if
* any of the pointers except |session_key| are NULL,
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures.
* OEMCrypto_SUCCESS otherwise.
*
* Caller retains ownership of all pointers.
*
* @param[in] key: handle with ECC key, required for derivation.
* @param[in] key_source: an ephemeral ECC public key used in ECDH.
* @param[in] key_source_length: length of |key_source|
* @param[out] session_key: destination buffer for derivated session key
* @param[in,out] session_key_length: size of |session_key| buffer, may
* be modified based on used/required space of output.
*/
OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key,
const uint8_t* key_source,
size_t key_source_length,
uint8_t* session_key,
size_t* session_key_length);
/**
* Gets the maximum RSA or ECC signature size from |key| and places the result
* in |signature_length|.
* Note, it is possible that the signature generate by this key be a few bytes
* shorter depending on the actual signature value.
*
* Returns
* OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL
* OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures
* OEMCrypto_SUCCESS otherwise
*
* Caller retains ownership of all pointers.
*
* @param[in] key: input key handle
* @param[out] signature_length: max size of the signature generated
* by |key|.
*/
OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key,
size_t* signature_length);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_CRYPTO_ASYMMETRIC_INTERFACE_H_ */

View File

@@ -0,0 +1,74 @@
/* 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_WTPI_DECRYPT_SAMPLE_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_DECRYPT_SAMPLE_INTERFACE_H_
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_output.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup decrypt-sample Sample Decrypt
*
* Data arrives in OEMCrypto in the form of samples made up of smaller
* subsamples. Interpreting the subsamples to know which bytes should be left
* clear or decrypted and what IV to use for the latter is non-trivial. Some
* devices have dedicated hardware for doing decryption of a full sample in one
* pass, skipping and decrypting bytes as appropriate. On such devices,
* decrypting the subsamples piecemeal is inefficient. But other devices can
* only decrypt one portion of a subsample at a time.
*
* The Sample Decryption interface defines decryption in terms of full
* samples. If your device has hardware support for full-sample decryption, you
* will get the best performance by implementing this layer yourself.
*
* However, if your device does not have support for hardware full-sample
* decryption, you may find it simpler to use the reference implementation of
* this layer. This implementation will handle interpreting the subsamples for
* you and send the decryption to the WTPIs other cryptography interfaces one
* subsample at a time.
*
* @{
*/
/**
* Decrypt Sample layer defines the interface between the OEMCrypto TA and the
* implementation of sample decryption.
*
* Partners implementing the Decrypt Sample porting layer may either
* 1. Implement their own wtpi_decrypt_sample_interface.h. This is preferred if
* the device has hardware support for full-sample decryption, or
* 2. Use the reference implementation decrypt_sample.c. This is preferred when
* there is no hardware support for full-sample decryption. The reference
* implementation will split the subsamples and decrypt them individually using
* the crypto_and_key_management_interface_layer1 component.
*/
/**
* Decrypts one sample |sample| with the specified |pattern| and |cipher_mode|
* using the |key_handle| to the current content key, into buffer
* |output_buffer| starting at an offset |output_offset|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL or
* invalid, or the result of DecryptSubsample if failing to decrypt any
* subsample, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all parameters.
*/
OEMCryptoResult WTPI_DecryptSample(
WTPI_K1_SymmetricKey_Handle key_handle,
const OEMCrypto_SampleDescription* sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const OPK_OutputBuffer* output_buffer, size_t output_offset,
OEMCryptoCipherMode cipher_mode);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_DECRYPT_SAMPLE_INTERFACE_H_ */

View File

@@ -0,0 +1,45 @@
/* 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_WTPI_DEVICE_KEY_ACCESS_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_DEVICE_KEY_ACCESS_INTERFACE_H_
#include <stdint.h>
#include "oemcrypto_key_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup dev-key-access Device Key Access
*
* This is a lower level of the WTPI device key package. The OPK does not
* directly call functions in this API. Partners have the option to implement
* this API and use Widevine's reference implementation of the layer 1 interface
* which wraps around the functions in this API, or instead implement all of the
* [Device Key layer 1](dev-key) functions.
*
* @{
*/
/** Returns the device unique key.
*
* @return The device unique key.
* */
const uint8_t* WTPI_GetDeviceKey(void);
/** Returns the size of the device key.
*
* @return The size of the device unique key.
* */
KeySize WTPI_GetDeviceKeySize(void);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_DEVICE_KEY_ACCESS_INTERFACE_H_ */

View File

@@ -0,0 +1,95 @@
/* 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_WTPI_DEVICE_KEY_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_DEVICE_KEY_INTERFACE_H_
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup dev-key Device Keys
*
* This is the top layer of the porting layer. The OPK directly calls functions
* in this file. Partners have the option to implement these functions directly,
* or use the reference version of the device key interface functions, and
* instead implement the device key access functions.
*
* @{
*/
/* The types of device specific keys that can be generated are as follows. */
/** A device unique key for encrypting/signing the usage table data. This key
* must be unique to this device so that usage tables may not be copied from one
* device to another.
* This should be used as a key derivation context in
* WTPI_K1_DeriveDeviceKeyIntoHandle().
*/
#define DEVICE_KEY_WRAP_USAGE_TABLE 0x22d8fdcf
/** A device unique key for encrypting/signing the private key in the DRM
* certificate. This key must be unique to this device so that a DRM certificate
* not be copied from one device to another.
* This should be used as a key derivation context in
* WTPI_K1_DeriveDeviceKeyIntoHandle().
*/
#define DEVICE_KEY_WRAP_DRM_CERT 0x1db2a411
/** A device unique key for encrypting the internal key used by the
* implementation of the key management layer. This should be used as a key
* derivation context in WTPI_K1_DeriveDeviceKeyIntoHandle().
*/
#define DEVICE_KEY_WRAP_INTERNAL_KEY 0x604e77a1
/** A device unique key for signing the wrapped internal key used by the
* implementation of the key management layer. This should be used as a key
* derivation context in WTPI_K1_DeriveDeviceKeyIntoHandle().
*/
#define DEVICE_KEY_SIGN_INTERNAL_KEY 0x90b4a189
/** A device unique key for encrypting the mac keys in usage entry.
*/
#define DEVICE_KEY_WRAP_MAC_KEY 0x125cc98d
/**
* Gets the size (in bytes) of the buffer needed by WTPI_EncryptAndSign to
* handle a buffer of the given size (in bytes). The return value should
* include |in_size| in the result.
*/
OEMCryptoResult WTPI_GetEncryptAndSignSize(uint32_t context, size_t in_size,
size_t* wrapped_size);
/**
* Encrypts the given buffer and signs it in a way that can be verified later.
* How this is done is implementation-defined. The encryption should be
* device-specific so it can't be used on another device. This should check the
* buffer size and return OEMCrypto_ERROR_SHORT_BUFFER if there isn't enough
* space. The input needs to be padded to a multiple of 16 bytes.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_EncryptAndSign(uint32_t context, const uint8_t* data,
size_t data_size, uint8_t* out,
size_t* out_size);
/**
* Verifies the buffer has a valid signature and decrypts it into the given
* buffer. This should return OEMCrypto_ERROR_SIGNATURE_FAILURE if the
* signature fails. This should check the buffer size and return
* OEMCrypto_ERROR_SHORT_BUFFER if there isn't enough space. If the input is
* padded, the padding is included in the output.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* wrapped,
size_t wrapped_size, uint8_t* out,
size_t* out_size);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_DEVICE_KEY_INTERFACE_H_ */

View File

@@ -0,0 +1,97 @@
/* Copyright 2020 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_GENERATION_NUMBER_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_GENERATION_NUMBER_INTERFACE_H_
#include <stdint.h>
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup gen-number Generation Number
*
* OEMCrypto needs to store the usage tables generation number in persistent
* storage with antirollback protection. Persistent storage for the generation
* number should have antirollback protection, such as RPMB.
*
* Partners implementing a porting layer may either
* 1. Implement wtpi_persistent_storage.h and wtpi_clock_interface_layer2.h,
* and then use the reference implementation clock_and_gn_layer1.c for the
* clock and generation interfaces. This is preferred if the hardware secure
* timer resets to 0 whenever the device is inactive.
* or
* 2. Implement both wtpi_clock_interface_layer1.h and
* this wtpi_generation_number_interface.h. This is preferred if the system
* has a hardware secure wall clock.
* @{
*/
/**
* Prepare to load the generation number. If the generation number is loaded
* asynchronously, this should initialize that process so that the next call to
* WTPI_LoadGenerationNumber does not block for too long.
*
* TODO(b/160022428): define and document "too long".
*
* The generation number should be stored in secure persistent storage. By
* *persistent* we mean that the generation number should not be changed by
* shutting down and later restarting the system. By *secure* we mean that the
* user should not be able to modify the generation number. In particular, the
* user should not be able to revert the generation number to a previous value.
*
* Returns OEMCrypto_SUCCESS on success. On failure, initialization of the TA
* will fail.
*/
OEMCryptoResult WTPI_PrepareGenerationNumber(void);
/**
* Load the usage table generation number. This is called once, on first use of
* the usage table. This is expected to block until a value is available. It is
* the porting interface's responsibility to fail if this blocks too
* long. Returns OEMCrypto_SUCCESS on success. Other return values will fail the
* OEMCrypto initialization. If the generation number has never been saved
* before, a random number should be generated -- this is NOT an error.
*
* @param[out] value: pointer to generation number.
*/
OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value);
/**
* Save the generation number.
*
* If the generation number is saved asynchronously, then it is OK for the first
* call to this function to begin a save process and then return
* OEMCrypto_SUCCESS. Subsequent calls will verify that the previous save has
* completed successfully. If the previous save resulted in an error, then this
* call will return an error. If the previous call has not completed, then this
* call should block until the previous save finishes before initializing a new
* save. If the previous call was successful, then this call will initialize a
* new save and return OEMCrypto_SUCCESS. It is the porting interface's
* responsibility to fail if this blocks too long.
*
* If the generation number is saved synchronously, then this function should
* attempt to save the generation number and return OEMCrypto_SUCCESS if the
* save was successful.
*
* Returns OEMCrypto_SUCCESS on success. Other return values will fail the
* current attempt to save the usage table. If a failure actually indicates that
* the previous save had failed, then the usage table will be saved with a
* generation number skew of 1. When the usage table is loaded with a generation
* skew of 1, it will result in a warning, but not a failure.
*
* @param[in] value: generation number.
*/
OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_GENERATION_NUMBER_INTERFACE_H_ */

View File

@@ -0,0 +1,55 @@
/* Copyright 2019 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_INITIALIZE_TERMINATE_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_INITIALIZE_TERMINATE_INTERFACE_H_
#include "OEMCryptoCENCCommon.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @mainpage Widevine TEE Porting Layer API
*
* The Widevine TEE Porting Interface (WTPI) is a collection of headers that
* define the interface between the OPK TA code and system-specific or
* hardware-specific features. Together, they define the abstraction layer
* between the TA code and the hardware. Each header file defines a set of
* related functions. It is your responsibility to provide an implementation for
* each WTPI function. The TA will not compile without implementations of all
* the WTPI components.
*
* See the [integration guide](../../../integration#wtpi-components) for a list
* of all WTPI components.
*/
/** @defgroup init-term Initialization/Termination
*
* This interface defines functions that will be called when the OEMCrypto is
* initialized or terminated. They can be used to do any initial setup or
* cleanup that you need to do for the TA to be operational. It is also
* acceptable for these functions to do nothing.
*
* @{
*/
/**
* Set up for any work needed for initializing the TA-specific components of the
* TEE. Returns OEMCrypto_SUCCESS on success and an error, which will be logged,
* on failure. */
OEMCryptoResult WTPI_Initialize(void);
/**
* Set up for any work needed for terminating the TA-specific components of the
* TEE. Returns OEMCrypto_SUCCESS on success and an error, which will be logged,
* on failure. */
OEMCryptoResult WTPI_Terminate(void);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_INITIALIZE_TERMINATE_INTERFACE_H_ */

View File

@@ -0,0 +1,60 @@
/* Copyright 2019 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_LOGGING_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_LOGGING_INTERFACE_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup logging Logging
*
* The OPK TA can log both debug and error messages. Log messages are sent to
* this API.
*
* Turn on debug logging by compiling with the switch -DOPK_DEBUG_LOGGING_ON.
* A production device should not have debug logging turned on.
*
* @{
*/
/** Log priorities that should be logged. LOG_DEBUG should only be logged on
* non-production devices.
*/
typedef enum LogPriority {
LOG_NONE = (int)0xf7bd0dc7,
LOG_ERROR = (int)0x1098fa73,
LOG_DEBUG = (int)0x2b898c5a,
} LogPriority;
/** Log the string at the specified log priority.
*
* If possible, the file, function and line number should also be
* logged. Logging should use the format string using standard printf formatting
* and the following parameters.
*
* @param[in] file: the name of the file containing the log statement.
* @param[in] function: the name of the function containing the log statement.
* @param[in] line: the line number of the log statement.
* @param[in] level: the log level of the log statement.
* @param[in] fmt: printf style log format.
*
*/
#ifdef __GNUC__
__attribute__((format(printf, 5, 6)))
#endif
void WTPI_Log(const char* file, const char* function, int line, LogPriority level, const char* fmt, ...);
/// @}
#define LOGE(...) WTPI_Log(__FILE__, __func__, __LINE__, LOG_ERROR, __VA_ARGS__)
#define LOGD(...) WTPI_Log(__FILE__, __func__, __LINE__, LOG_DEBUG, __VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_LOGGING_INTERFACE_H_ */

View File

@@ -0,0 +1,109 @@
/* 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_WTPI_PERSISTENT_STORAGE_INTERFACE_H_
#define OEMCRYPTO_TA_WTPI_PERSISTENT_STORAGE_INTERFACE_H_
#include "stdint.h"
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup persistent Persistent Storage
*
* Partners implementing a porting layer may either
* 1. Implement this wtpi_persistent_storage.h and
* wtpi_clock_interface_layer2.h, and then use the reference implementation
* clock_and_gn_layer1.c for the clock and generation interfaces. This is
* preferred if the hardware secure timer resets to 0 whenever the device is
* inactive.
* or
* 2. Implement both wtpi_clock_interface_layer1.h and
* wtpi_generation_number_interface.h. This is preferred if the system has a
* hardware secure wall clock.
*
* @{
*/
/**
* Prepare to load the stored data. If the data is loaded asynchronously,
* this should initialize that process so that the next call to
* WTPI_LoadPersistentData does not block for too long.
*
* TODO(b/160022428): define and document "too long".
*
* The values should be stored in secure persistent storage. By *persistent* we
* mean that the value should not be changed by shutting down and later
* restarting the system. By *secure* we mean that the user should not be able
* to modify the values.
*
* Returns OEMCrypto_SUCCESS on success. On failure, initialization of the TA
* will fail.
*/
OEMCryptoResult WTPI_PrepareStoredPersistentData(void);
/**
* Load the persistent data. This is called once, on first use of the clock or
* generation number. This is expected to block until a value is available. It
* is the porting interface's responsibility to fail if this blocks too long. In
* order to support data layout changes across upgrade, this function should
* return less data than requested if necessary. If the available data is less
* than |*data_length|, it should fill |data| with the available data and it
* should change |*data_length| to be the amount of available data, and it
* should return OEMCrypto_SUCCESS. If there is more data available than will
* fit in |data|, then it should return OEMCrypto_ERROR_SHORT_BUFFER.
*
* The layer above this function is responsible for handling data format changes
* and backwards compatibility across upgrades.
*
* @retval OEMCrypto_SUCCESS data was loaded.
* @retval OPK_ERROR_NO_PERSISTENT_DATA No data available.
* @retval OEMCrypto_ERROR_SHORT_BUFFER more than |data_length| data available.
*
* @param[out] data: pointer to persistent data.
* @param[in/out] data_length: on input, the size of the data buffer, on out
* the amount of data that was loaded.
*/
OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length);
/**
* Save the persistent data.
*
* If the data is saved asynchronously, then it is OK for the first
* call to this function to begin a save process and then return
* OEMCrypto_SUCCESS. Subsequent calls will verify that the previous save has
* completed successfully. If the previous save resulted in an error, then this
* call will return an error. If the previous call has not completed, then this
* call should block until the previous save finishes before initializing a new
* save. If the previous call was successful, then this call will initialize a
* new save and return OEMCrypto_SUCCESS. It is the porting interface's
* responsibility to fail if this blocks too long.
*
* If the data is saved synchronously, then this function should attempt to save
* the generation number and return OEMCrypto_SUCCESS if the save was
* successful.
*
* Returns OEMCrypto_SUCCESS on success. Other return values will fail the
* current attempt to save the usage table. If a failure actually indicates that
* the previous save had failed, then the usage table will be saved with a
* generation number skew of 1. When the usage table is loaded with a generation
* skew of 1, it will result in a warning, but not a failure.
*
*
* @param[in] data: persistent data.
* @param[in] data_length: the amount of data to save.
*/
OEMCryptoResult WTPI_StorePersistentData(const uint8_t* data,
size_t data_length);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_PERSISTENT_STORAGE_INTERFACE_H_ */

View File

@@ -0,0 +1,83 @@
/* Copyright 2019 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_ROOT_OF_TRUST_INTERFACE_LAYER1_H_
#define OEMCRYPTO_TA_WTPI_ROOT_OF_TRUST_INTERFACE_LAYER1_H_
#include "stddef.h"
#include "stdint.h"
#include "OEMCryptoCENC.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup layer1-rot Layer 1 Root Of Trust
* Keybox access functions called directly by OPK code.
*
* This is the top layer of the porting layer. The OPK directly calls
* functions in this file. Partners have the option to implement these functions
* directly, or use the reference version of the layer 1 functions, and instead
* implement the layer 2 functions.
*
* @{
*/
/** Initialize all necessary data. */
OEMCryptoResult WTPI_InitializeKeybox(void);
/** Terminate anything that needs terminating. */
OEMCryptoResult WTPI_TerminateKeybox(void);
/** Unwrap and store the buffer in non-persistent memory reserved for ROT.
This is used once in the factory to install the real keybox.
If possible, in order to avoid buffer overflow attacks, we recommend
partners to keep this separate from the device key in the keybox, so that
when this accessed, the device key is not exposed.
It may be wise to make this function a no-op when the device is not in
factory mode.
*/
OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input,
size_t length);
/** Attempt to validate the current keybox loaded. Returns
OEMCrypto_ERROR_BAD_MAGIC if magic field is not "kbox",
OEMCrypto_ERROR_BAD_CRC if computed CRC is not equivalent to stored CRC, and
OEMCrypto_SUCCESS otherwise. */
OEMCryptoResult WTPI_ValidateKeybox(void);
/** Get the 72 byte encrypted key data from the current keybox. Returns
OEMCrypto_ERROR_INVALID_CONTEXT if |key_data| is NULL and OEMCrypto_SUCCESS
otherwise. |key_data| must be >= 72 bytes. */
OEMCryptoResult WTPI_GetKeyDataFromKeybox(uint8_t* key_data, size_t length);
/** Load a test keybox to be used until the next OEMCrypto_Terminate call.
Returns OEMCrypto_ERROR_INVALID_CONTEXT if |test_keybox| is NULL and
OEMCrypto_SUCCESS otherwise. |test_keybox| must be >= 128 bytes. */
OEMCryptoResult WTPI_LoadTestKeybox(const uint8_t* test_keybox, size_t length);
/** Create a key handle from the device key in the keybox. The caller is
* responsible for calling WTPI_K1_FreeKeyHandle on out when the key is no
* longer needed. */
OEMCryptoResult WTPI_K1_CreateKeyHandleFromKeybox(
WTPI_K1_SymmetricKey_Handle* out);
/** Gets the device id from the current provisioning method. Returns
OEMCrypto_ERROR_INVALID_CONTEXT if |device_id| is NULL, or |device_id_length|
is smaller than KEYBOX_DEVICE_ID_SIZE, and OEMCrypto_SUCCESS otherwise. If
the keybox is used, sets |device_id| with the device id in keybox. Caller
retains ownership of all pointers. */
OEMCryptoResult WTPI_GetDeviceIDFromKeybox(uint8_t* device_id,
size_t device_id_length);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_ROOT_OF_TRUST_INTERFACE_LAYER1_H_ */

View File

@@ -0,0 +1,67 @@
/* Copyright 2019 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_ROOT_OF_TRUST_INTERFACE_LAYER2_H_
#define OEMCRYPTO_TA_WTPI_ROOT_OF_TRUST_INTERFACE_LAYER2_H_
#include "stddef.h"
#include "stdint.h"
#include "OEMCryptoCENC.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup layer2-rot Layer 2 Root Of Trust
* Hardware level access to root of trust.
*
* These functions provide a simple interface to the hardware secure persistent
* storage. Partners may choose to implement these functions and use the layer
* 1 code provided by Widevine to present a higher level interface.
*
* These functions should be easier to implement, but using the layer 1
* functions may reduce performance or security.
*
* @{
*/
/** Use the system specific key to unwrap the root of trust buffer. This
* function is used in the factory.
*
* input [in]: buffer with encrypted root of trust.
* input_length [in]: the length of the input.
* output [out]: buffer where clear root of trust will be written.
* output_length [in/out]: on input, it's the buffer size, on output it's how
* much was unwrapped. If output_length is too short for the entire root of
* trust, the error code OEMCrypto_ERROR_SHORT_BUFFER shall be returned.
*/
OEMCryptoResult WTPI_UnwrapRootOfTrust(const uint8_t* input,
size_t input_length, uint8_t* output,
size_t* output_length);
/** Save the buffer to secure permanent storage.
* To prevent accidentally destroying the keybox, production devices should
* return an error code if this function is called when the device is not in
* "factory mode".
*/
OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* keybox, size_t length);
/** Read the buffer from secure permanent storage.
*
* keybox [in]: buffer of the keybox.
* length [in/out]: on input, it's the buffer size, on output it's the actual
* size loaded into the buffer. If length is too short for the entire root
* of trust, the error code OEMCrypto_ERROR_SHORT_BUFFER shall be returned.
* Otherwise, set length to the size of the root of trust loaded.
*/
OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* keybox, size_t* length);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_WTPI_ROOT_OF_TRUST_INTERFACE_LAYER2_H_ */

View File

@@ -0,0 +1,37 @@
/* 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_SECURE_BUFFER_ACCESS_H_
#define OEMCRYPTO_TA_SECURE_BUFFER_ACCESS_H_
#include "OEMCryptoCENCCommon.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup secure-buffer Secure Buffer Access
*
* Interface used by the reference [sample decryption
* interface])(decrypt-sample) to access secure buffers.
*
* @{
*/
/**
* Get the secure buffer address given a pointer to the secure memory with an
* offset, and places it in |out_addr|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the parameters are NULL or
* invalid, and OEMCrypto_SUCCESS otherwise.
*/
OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset,
uint8_t** out_addr);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_SECURE_BUFFER_ACCESS_H_ */

View File

@@ -0,0 +1,211 @@
/* 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 <inttypes.h>
#include <string.h>
#include <time.h>
#include "OEMCryptoCENC.h"
#include "oemcrypto_wall_clock.h"
#include "wtpi_clock_interface_layer2.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_logging_interface.h"
#include "wtpi_persistent_storage.h"
static bool gInitialized = false;
// The most recent trusted time.
static uint64_t gLastTime;
// The last saved value of the wall clock.
static uint64_t gSavedWallClock;
// Difference between hardware clock and trusted clock.
static int64_t gClockDelta;
static uint64_t gSavedGenerationNumber;
typedef struct WTPI_PersistentData {
uint64_t generation_number;
uint64_t previous_wall_clock;
uint64_t previous_trusted_time;
} WTPI_PersistentData;
#define PERSISTENT_FORMAT_VERSION_NUMBER 1
#define PERSISTENT_DATA_SIZE (1 + sizeof(WTPI_PersistentData))
#define EARLIEST_REASONABLE_TIME 1587470400 // Year 2020.
#define PERIODIC_SAVE_TIME (60 * 15) // Save every 15 minutes.
static uint64_t gLastSaveTime;
// Initialize the clock delta based on the saved wall clock time.
static OEMCryptoResult InitializeDelta(void) {
gClockDelta = 0;
uint64_t hw_timer = 0;
OEMCryptoResult status = WTPI_GetSecureTimer(&hw_timer);
if (status != OEMCrypto_SUCCESS) return status;
uint64_t wall_clock = 0;
status = OPK_GetWallClockTime(&wall_clock);
if (status != OEMCrypto_SUCCESS) return status;
// If we have reasonable wall clock times, and it increased since we last
// saved it, assume that our system time should also increase by that much.
// This is a one-time increment because we assume that the wall clock's
// increment is more reliable while the system is off than the hardware clock.
if (wall_clock > EARLIEST_REASONABLE_TIME &&
gSavedWallClock > EARLIEST_REASONABLE_TIME &&
wall_clock > gSavedWallClock) {
uint64_t sleep_time = wall_clock - gSavedWallClock;
gLastTime += sleep_time;
LOGD("Init clock from sleep time = %" PRIu64 " = %" PRIu64 " - %" PRIu64,
sleep_time, wall_clock, gSavedWallClock);
}
// After that onetime increment, we should advance the clock in sync with the
// hardware clock. Here we compute the delta between our system clock and the
// hardware clock.
gClockDelta = gLastTime - hw_timer;
LOGD("Init clock with new delta: %" PRId64 " = %" PRIu64 " - %" PRIu64,
gClockDelta, gLastTime, hw_timer);
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult InitializeData(void) {
gInitialized = true;
size_t data_length = PERSISTENT_DATA_SIZE;
uint8_t buffer[PERSISTENT_DATA_SIZE];
OEMCryptoResult status = WTPI_LoadPersistentData(buffer, &data_length);
uint8_t version_number = buffer[0];
if (status == OPK_ERROR_NO_PERSISTENT_DATA ||
data_length != PERSISTENT_DATA_SIZE ||
version_number != PERSISTENT_FORMAT_VERSION_NUMBER) {
// Note: In the future, we may wish to handle older version numbers.
// This is the first initialization. Start the generation number at random
// value and the clock at 0.
status = WTPI_C1_RandomBytes((uint8_t*)(&gSavedGenerationNumber),
sizeof(uint64_t));
LOGD("New random generation number.");
if (status != OEMCrypto_SUCCESS) return status;
gClockDelta = 0;
gLastSaveTime = 0;
status = WTPI_GetSecureTimer(&gLastTime);
LOGD("Initializing new clock delta = 0, last = %" PRIu64, gLastTime);
return status;
} else {
WTPI_PersistentData data;
memcpy(&data, buffer + 1, sizeof(data));
gSavedGenerationNumber = data.generation_number;
gLastTime = data.previous_trusted_time;
gSavedWallClock = data.previous_wall_clock;
gLastSaveTime = gLastTime;
status = InitializeDelta();
LOGD("Loading saved generation: %" PRIu64, gSavedGenerationNumber);
LOGD("Initializing clock w/last = %" PRIu64 ", last wall = %" PRIu64
", delta = %" PRId64,
gLastTime, gSavedWallClock, gClockDelta);
return status;
}
}
static OEMCryptoResult SaveData(void) {
if (!gInitialized) return OEMCrypto_ERROR_INVALID_CONTEXT;
WTPI_PersistentData data;
// Save the most recent wall clock value, if it's reasonable. Otherwise keep
// the previous saved value.
uint64_t wall_clock = 0;
OEMCryptoResult status = OPK_GetWallClockTime(&wall_clock);
if (status != OEMCrypto_SUCCESS) return status;
data.previous_wall_clock =
wall_clock > EARLIEST_REASONABLE_TIME ? wall_clock : gSavedWallClock;
data.previous_trusted_time = gLastTime;
data.generation_number = gSavedGenerationNumber;
LOGD("Store generation number = %" PRIu64, gSavedGenerationNumber);
gLastSaveTime = gLastTime;
LOGD("Saving wall clock = %" PRIu64 ", system time = %" PRId64 ".",
data.previous_wall_clock, data.previous_trusted_time);
size_t data_length = PERSISTENT_DATA_SIZE;
uint8_t buffer[PERSISTENT_DATA_SIZE];
buffer[0] = PERSISTENT_FORMAT_VERSION_NUMBER;
memcpy(buffer + 1, &data, sizeof(data));
return WTPI_StorePersistentData(buffer, data_length);
}
/******************************************************************************
The following implement the generation number interface.
*******************************************************************************/
OEMCryptoResult WTPI_PrepareGenerationNumber(void) {
return WTPI_PrepareStoredPersistentData();
}
OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) {
LOGD("Load generation number.");
if (!gInitialized) {
OEMCryptoResult status = InitializeData();
if (status != OEMCrypto_SUCCESS) return status;
}
if (!value) return OEMCrypto_ERROR_INVALID_CONTEXT;
*value = gSavedGenerationNumber;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) {
LOGD("Save generation number.");
if (!gInitialized) {
// This is only done in the tests. In real life, we attempt to load the old
// GN before we ever save a new one.
OEMCryptoResult status = InitializeData();
if (status != OEMCrypto_SUCCESS) return status;
}
gSavedGenerationNumber = value;
return SaveData();
}
/******************************************************************************
The following implement the clock interface.
*******************************************************************************/
OEMCryptoResult WTPI_InitializeClock(void) {
LOGD("Initialize clock.");
gInitialized = false;
gLastTime = 0;
gSavedWallClock = EARLIEST_REASONABLE_TIME;
gClockDelta = 0;
gLastSaveTime = 0;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_TerminateClock(void) {
LOGD("Terminate clock.");
if (!gInitialized) return OEMCrypto_SUCCESS;
return SaveData();
}
OEMCrypto_Clock_Security_Level WTPI_GetClockType(void) { return kSecureTimer; }
OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) {
OEMCryptoResult status = OEMCrypto_SUCCESS;
if (!gInitialized) {
LOGD("Clock needs to initialize.");
status = InitializeData();
if (status != OEMCrypto_SUCCESS) return status;
}
uint64_t hw_timer = 0;
status = WTPI_GetSecureTimer(&hw_timer);
uint64_t now = hw_timer + gClockDelta;
// If the hardware clock goes backwards, or the clock delta has not been
// initialized by the saved wall clock, then now might be less than the last
// time. In that case, we increase the delta so that our clock continues to
// move forward.
if (now < gLastTime) {
gClockDelta = gLastTime - hw_timer;
now = gLastTime;
LOGD("Clock drift. update now = %" PRIu64 ", and delta %" PRId64
" = %" PRIu64 " - %" PRIu64,
now, gClockDelta, gLastTime, hw_timer);
} else {
gLastTime = now;
}
*time_in_s = now;
if (now > gLastSaveTime + PERIODIC_SAVE_TIME) {
LOGD("Periodic clock save. now = %" PRIu64 ", last save = %" PRIu64, now,
gLastSaveTime);
SaveData();
}
return status;
}

View File

@@ -0,0 +1,110 @@
/* 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_crc32_interface.h"
#include "oemcrypto_overflow.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_secure_buffer_access_interface.h"
#define INIT_CRC32 0xffffffff
static uint32_t wvrunningcrc32(const uint8_t* in, size_t in_length,
uint32_t prev_crc) {
static const uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
/* Calculate the CRC */
while (in_length > 0) {
prev_crc = (prev_crc << 8) ^ CRC32[(prev_crc >> 24) ^ ((uint32_t)(*in))];
in++;
in_length--;
}
return prev_crc;
}
OEMCryptoResult WTPI_Crc32Init(uint32_t* initial_hash) {
if (initial_hash == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*initial_hash = INIT_CRC32;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_Crc32Cont(const uint8_t* in, size_t in_length,
uint32_t prev_crc, uint32_t* new_crc) {
if (in == NULL || in_length == 0 || new_crc == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
*new_crc = wvrunningcrc32(in, in_length, prev_crc);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_Crc32Cont_OutputBuffer(const OPK_OutputBuffer* in,
size_t in_offset, size_t in_length,
uint32_t prev_crc,
uint32_t* new_crc) {
size_t total_size;
if (OPK_AddOverflowUX(in_offset, in_length, &total_size)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (in == NULL || in_length == 0 || new_crc == NULL ||
total_size > in->size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* src = NULL;
if (in->type == OPK_SECURE_OUTPUT_BUFFER) {
OEMCryptoResult result =
WTPI_GetSecureBufferAddress(in->buffer.secure, in_offset, &src);
if (result != OEMCrypto_SUCCESS) return result;
} else if (in->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) {
src = in->buffer.clear_insecure + in_offset;
} else {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
*new_crc = wvrunningcrc32(src, in_length, prev_crc);
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,746 @@
/* 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_layer1.h"
#include <stdint.h>
#include <stdlib.h> /* THIS IS TEMPORARY UNTIL WE GET AN ALLOCATOR. */
#include <string.h>
#include "OEMCryptoCENCCommon.h"
#include "key_mapping_interface.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_object_table.h"
#include "oemcrypto_overflow.h"
#include "openssl/rand.h"
#include "openssl/x509.h"
#include "wtpi_abort_interface.h"
#include "wtpi_config_macros.h"
#include "wtpi_crypto_and_key_management_interface_layer2.h"
#include "wtpi_device_key_interface.h"
#include "wtpi_logging_interface.h"
#include "wtpi_secure_buffer_access_interface.h"
/******************************************************************************
* This is a reference implementation of Crypto and Key Management layer 1,
* which aims to work with an underlying hardware-backed cryptography. The keys
* in this layer are encrypted and signed by a device specific key, and are
* stored in a pre-allocated table, before used by the hardware crypto.
******************************************************************************/
/** Wrapped key data to be saved in key management layer 1 table. */
typedef struct WrappedKeyData {
uint8_t iv[KEY_IV_SIZE];
uint8_t wrapped_key[MAX_WRAPPED_SYMMETRIC_KEY_SIZE];
} WrappedKeyData;
/** Signed and wrapped key data to be saved in key management layer 1 table. */
typedef struct SignedWrappedKeyData {
uint8_t signature[SHA256_DIGEST_LENGTH];
WrappedKeyData wrapped_key_data;
} SignedWrappedKeyData;
typedef struct WTPI_K1_SymmetricKey {
SymmetricKeyType key_type;
KeySize key_size;
SignedWrappedKeyData key_data;
bool is_loaded;
uint32_t index_loaded;
} WTPI_K1_SymmetricKey;
typedef struct wtpi_k1_symmetric_key_handle {
uint32_t index;
} wtpi_k1_symmetric_key_handle;
/**
* Key table used by key management layer 1. Keys in the table are wrapped by a
* device specific key. When being used, the key needs to be unwrapped and
* verified first, and then loaded into the key management layer 2 table.
*/
DEFINE_OBJECT_TABLE(key_table, WTPI_K1_SymmetricKey, MAX_NUMBER_OF_KEYS, NULL);
static OEMCryptoResult EncryptAndSignKey(WTPI_K2_SymmetricKey_Handle key_handle,
uint32_t context, uint8_t* out,
size_t out_size) {
if (key_handle == NULL || out == NULL ||
out_size < sizeof(SignedWrappedKeyData)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SignedWrappedKeyData* wrapped = (SignedWrappedKeyData*)out;
/* Pick a random IV for generating keys. */
OEMCryptoResult result = WTPI_C1_RandomBytes(
wrapped->wrapped_key_data.iv, sizeof(wrapped->wrapped_key_data.iv));
if (result != OEMCrypto_SUCCESS) return result;
// Encrypt the buffer.
WTPI_K2_SymmetricKey_Handle encryption_key_handle = NULL;
result = WTPI_K2_DeriveDeviceKeyIntoHandle(
context, ENCRYPTION_KEY, &encryption_key_handle, KEY_SIZE_128);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_K2_EncryptKeyHandle(key_handle, encryption_key_handle,
wrapped->wrapped_key_data.iv,
wrapped->wrapped_key_data.wrapped_key);
WTPI_K2_FreeKeyHandle(encryption_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
// Compute the signature of the data past the signature block and store it
// at the start of the output buffer.
WTPI_K2_SymmetricKey_Handle signing_key_handle = NULL;
result = WTPI_K2_DeriveDeviceKeyIntoHandle(DEVICE_KEY_SIGN_INTERNAL_KEY,
MAC_KEY_CLIENT,
&signing_key_handle, KEY_SIZE_256);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_C2_HMAC_SHA256(
signing_key_handle, (uint8_t*)(&wrapped->wrapped_key_data),
sizeof(wrapped->wrapped_key_data), wrapped->signature);
WTPI_K2_FreeKeyHandle(signing_key_handle);
return result;
}
static OEMCryptoResult VerifyAndDecryptKey(
uint32_t context, const uint8_t* wrapped_data, SymmetricKeyType key_type,
KeySize key_size, WTPI_K2_SymmetricKey_Handle* out_key_handle) {
if (wrapped_data == NULL || out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const SignedWrappedKeyData* wrapped =
(const SignedWrappedKeyData*)wrapped_data;
// Verify the signature first, before decrypting.
WTPI_K2_SymmetricKey_Handle signing_key_handle = NULL;
OEMCryptoResult result = WTPI_K2_DeriveDeviceKeyIntoHandle(
DEVICE_KEY_SIGN_INTERNAL_KEY, MAC_KEY_SERVER, &signing_key_handle,
KEY_SIZE_256);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_C2_HMAC_SHA256_Verify(
signing_key_handle, (uint8_t*)(&wrapped->wrapped_key_data),
sizeof(wrapped->wrapped_key_data), wrapped->signature);
WTPI_K2_FreeKeyHandle(signing_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
// Decrypt the buffer.
WTPI_K2_SymmetricKey_Handle encryption_key_handle = NULL;
result = WTPI_K2_DeriveDeviceKeyIntoHandle(
context, ENCRYPTION_KEY, &encryption_key_handle, KEY_SIZE_128);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_K2_AESDecryptAndCreateKeyHandle(
encryption_key_handle, wrapped->wrapped_key_data.wrapped_key,
(size_t)key_size, wrapped->wrapped_key_data.iv, key_type, out_key_handle);
WTPI_K2_FreeKeyHandle(encryption_key_handle);
return result;
}
static bool IsKeyValid(uint32_t index) {
WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, index);
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->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256;
case ENTITLEMENT_KEY:
case MAC_KEY_SERVER:
case MAC_KEY_CLIENT:
return key->key_size == KEY_SIZE_256;
case ENCRYPTION_KEY:
case DERIVING_KEY:
return key->key_size == KEY_SIZE_128;
}
}
static bool IsKeyHandleValid(WTPI_K1_SymmetricKey_Handle key_handle) {
return (key_handle != NULL && key_handle->index < MAX_NUMBER_OF_KEYS &&
IsKeyValid(key_handle->index));
}
static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle,
SymmetricKeyType* type) {
if (key_handle == NULL || type == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, key_handle->index);
*type = key->key_type;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle,
KeySize* size) {
if (key_handle == NULL || size == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, key_handle->index);
*size = key->key_size;
return OEMCrypto_SUCCESS;
}
/******************************************************************************
The following implement the key mapping interface.
*******************************************************************************/
typedef struct KeyHandlePair {
WTPI_K2_SymmetricKey_Handle k2_key_handle;
WTPI_K1_SymmetricKey_Handle k1_key_handle;
} KeyHandlePair;
// |gHandlePairTable| does the book-keeping of all allocated layer 2 key handles
// which have a layer 1 key handle counterpart. A layer 2 key handle which
// doesn't have a corresponding layer 1 key handle is not tracked by this table.
// Such a key handle is a temporary handle and should be freed right after use.
// So, it doesn't have to be tracked.
static KeyHandlePair gHandlePairTable[MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES];
WTPI_K2_SymmetricKey_Handle KM_LookupKeyHandle(
WTPI_K1_SymmetricKey_Handle k1_key_handle, bool reload_required) {
ABORT_IF(!IsKeyHandleValid(k1_key_handle), "Impossible key handle.");
WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL;
uint32_t k1_index = k1_key_handle->index;
WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, k1_index);
if (key->is_loaded) {
uint32_t k2_index = key->index_loaded;
k2_key_handle = gHandlePairTable[k2_index].k2_key_handle;
}
if (k2_key_handle == NULL && reload_required) {
OEMCryptoResult result = VerifyAndDecryptKey(
DEVICE_KEY_WRAP_INTERNAL_KEY, (uint8_t*)(&key->key_data), key->key_type,
key->key_size, &k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to reload layer 2 key handle with result: %u", result);
return NULL;
}
result = KM_PairKeyHandle(k1_key_handle, k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
LOGE(
"Failed to pair layer 1 key handle with layer 2 key handle with "
"result: %u",
result);
}
}
return k2_key_handle;
}
OEMCryptoResult KM_PairKeyHandle(WTPI_K1_SymmetricKey_Handle k1_key_handle,
WTPI_K2_SymmetricKey_Handle k2_key_handle) {
ABORT_IF(!IsKeyHandleValid(k1_key_handle) ||
!WTPI_K2_IsKeyHandleValid(k2_key_handle),
"Impossible key handle.");
uint32_t k2_index;
OEMCryptoResult result = KM_GetLayer2KeyIndex(k2_key_handle, &k2_index);
if (result != OEMCrypto_SUCCESS) return result;
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, k1_key_handle->index);
key->is_loaded = true;
key->index_loaded = k2_index;
gHandlePairTable[k2_index].k2_key_handle = k2_key_handle;
gHandlePairTable[k2_index].k1_key_handle = k1_key_handle;
return OEMCrypto_SUCCESS;
}
static void UnpairKeyHandle(uint32_t k2_index) {
ABORT_IF(!KM_IsLayer2KeyIndexValid(k2_index), "Impossible key index.");
WTPI_K1_SymmetricKey_Handle k1_key_handle =
gHandlePairTable[k2_index].k1_key_handle;
if (IsKeyHandleValid(k1_key_handle)) {
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, k1_key_handle->index);
key->is_loaded = false;
key->index_loaded = MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES;
}
gHandlePairTable[k2_index].k2_key_handle = NULL;
gHandlePairTable[k2_index].k1_key_handle = NULL;
}
OEMCryptoResult KM_EvictLayer2KeyByIndex(uint32_t k2_index) {
if (!KM_IsLayer2KeyIndexValid(k2_index)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
gHandlePairTable[k2_index].k2_key_handle;
if (k2_key_handle == NULL) {
// trying to evict a layer 2 key slot which is still waiting to be paired
// could indicate that we are running out of layer 2 key slots
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
OEMCryptoResult result = WTPI_K2_FreeKeyHandle(k2_key_handle);
UnpairKeyHandle(k2_index);
return result;
}
OEMCryptoResult AESCTRDecryptWithKeyHandle(
WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_AESCTRDecrypt(k2_key_handle, in, in_length, iv, block_offset,
out);
}
/******************************************************************************
The following implement the layer 1 crypto interface.
*******************************************************************************/
OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_AESCBCDecrypt(k2_key_handle, key_length, in, in_length, iv,
out);
}
OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_AESCBCEncrypt(k2_key_handle, in, in_length, iv, out);
}
OEMCryptoResult WTPI_C1_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_C1_HMAC_SHA1(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_HMAC_SHA1(k2_key_handle, message, message_length, out);
}
OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_HMAC_SHA256(k2_key_handle, message, message_length, out);
}
OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* message,
size_t message_length, const uint8_t* signature) {
if (key_handle == NULL || message == NULL || message_length == 0 ||
signature == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_C2_HMAC_SHA256_Verify(k2_key_handle, message, message_length,
signature);
}
/******************************************************************************
The following implement the layer 1 key management interface.
*******************************************************************************/
OEMCryptoResult WTPI_K1_InitializeKeyManagement(void) {
OPKI_UnsafeClearObjectTable(&key_table);
for (int i = 0; i < MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES; i++) {
memset(&gHandlePairTable[i], 0, sizeof(gHandlePairTable[i]));
}
OEMCryptoResult result = WTPI_K2_InitializeKeyManagement();
if (result != OEMCrypto_SUCCESS) return result;
KM_SetLayer2KeyEvictionCallback(&KM_EvictLayer2KeyByIndex);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_TerminateKeyManagement(void) {
return WTPI_K2_TerminateKeyManagement();
}
/** Create layer 1 key handle from a layer 2 key handle. */
static OEMCryptoResult K1_CreateKeyHandle(
WTPI_K2_SymmetricKey_Handle key_handle, SymmetricKeyType key_type,
KeySize key_size, WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (key_handle == NULL || out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!WTPI_K2_IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint32_t index;
WTPI_K1_SymmetricKey* key = OPKI_AllocFromObjectTable(&key_table, &index);
if (key == NULL) return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
// Encrypt and sign key
OEMCryptoResult result =
EncryptAndSignKey(key_handle, DEVICE_KEY_WRAP_INTERNAL_KEY,
(uint8_t*)(&key->key_data), sizeof(key->key_data));
if (result != OEMCrypto_SUCCESS) {
OPKI_FreeFromObjectTable(&key_table, key);
return result;
}
key->key_type = key_type;
key->key_size = key_size;
WTPI_K1_SymmetricKey_Handle handle =
malloc(sizeof(wtpi_k1_symmetric_key_handle));
if (handle == NULL) {
OPKI_FreeFromObjectTable(&key_table, key);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
handle->index = index;
*out_key_handle = handle;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_CreateKeyHandle(
const uint8_t* serialized_bytes, size_t size, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (serialized_bytes == NULL || size == 0 || out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(size);
if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL;
OEMCryptoResult result =
WTPI_K2_CreateKeyHandle(serialized_bytes, size, key_type, &k2_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
result =
K1_CreateKeyHandle(k2_key_handle, key_type, key_size, out_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
result = KM_PairKeyHandle(*out_key_handle, k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle(
uint32_t context, SymmetricKeyType out_key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) {
if (out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL;
OEMCryptoResult result = WTPI_K2_DeriveDeviceKeyIntoHandle(
context, out_key_type, &k2_key_handle, out_key_size);
if (result != OEMCrypto_SUCCESS) return result;
result = K1_CreateKeyHandle(k2_key_handle, out_key_type, out_key_size,
out_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
result = KM_PairKeyHandle(*out_key_handle, k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key,
size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(decrypt_key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (enc_key_length != KEY_SIZE_128 && enc_key_length != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_decrypt_key_handle =
KM_LookupKeyHandle(decrypt_key_handle, true);
if (k2_decrypt_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL;
OEMCryptoResult result = WTPI_K2_AESDecryptAndCreateKeyHandle(
k2_decrypt_key_handle, enc_key, enc_key_length, iv, key_type,
&k2_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
result = K1_CreateKeyHandle(k2_key_handle, key_type, (KeySize)enc_key_length,
out_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
result = KM_PairKeyHandle(*out_key_handle, k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys,
size_t enc_mac_keys_length, const uint8_t* iv,
WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
WTPI_K1_SymmetricKey_Handle* out_mac_key_client) {
if (decrypt_key_handle == NULL || enc_mac_keys == NULL ||
enc_mac_keys_length == 0 || out_mac_key_server == NULL ||
out_mac_key_client == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(decrypt_key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (enc_mac_keys_length != 2 * MAC_KEY_SIZE) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_decrypt_key_handle =
KM_LookupKeyHandle(decrypt_key_handle, true);
if (k2_decrypt_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
WTPI_K2_SymmetricKey_Handle k2_server_key_handle = NULL;
WTPI_K2_SymmetricKey_Handle k2_client_key_handle = NULL;
result = WTPI_K2_AESDecryptAndCreateKeyHandleForMacKeys(
k2_decrypt_key_handle, enc_mac_keys, enc_mac_keys_length, iv,
&k2_server_key_handle, &k2_client_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
result = K1_CreateKeyHandle(k2_server_key_handle, MAC_KEY_SERVER,
MAC_KEY_SIZE, out_mac_key_server);
if (result != OEMCrypto_SUCCESS) goto cleanup;
result = K1_CreateKeyHandle(k2_client_key_handle, MAC_KEY_CLIENT,
MAC_KEY_SIZE, out_mac_key_client);
if (result != OEMCrypto_SUCCESS) goto cleanup;
result = KM_PairKeyHandle(*out_mac_key_server, k2_server_key_handle);
if (result != OEMCrypto_SUCCESS) goto cleanup;
result = KM_PairKeyHandle(*out_mac_key_client, k2_client_key_handle);
if (result != OEMCrypto_SUCCESS) goto cleanup;
return OEMCrypto_SUCCESS;
cleanup:;
if (k2_server_key_handle != NULL) WTPI_K2_FreeKeyHandle(k2_server_key_handle);
if (k2_client_key_handle != NULL) WTPI_K2_FreeKeyHandle(k2_client_key_handle);
return result;
}
OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle(
WTPI_K1_SymmetricKey_Handle key_handle, uint8_t counter,
const uint8_t* context, size_t context_length,
SymmetricKeyType out_key_type, KeySize out_key_size,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (key_handle == NULL || context == NULL || context_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SymmetricKeyType key_type;
OEMCryptoResult result = GetKeyType(key_handle, &key_type);
if (result != OEMCrypto_SUCCESS || key_type != DERIVING_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
WTPI_K2_SymmetricKey_Handle k2_derived_key_handle = NULL;
result = WTPI_K2_DeriveKeyFromKeyHandle(k2_key_handle, counter, context,
context_length, out_key_type,
out_key_size, &k2_derived_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
result = K1_CreateKeyHandle(k2_derived_key_handle, out_key_type, out_key_size,
out_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_derived_key_handle);
return result;
}
result = KM_PairKeyHandle(*out_key_handle, k2_derived_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_derived_key_handle);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_WrapKey(uint32_t context,
WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, true);
if (k2_key_handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_K2_WrapKey(context, k2_key_handle, key_type, wrapped_key,
wrapped_key_length);
}
OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle(
uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length,
SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (wrapped_key == NULL || wrapped_key_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(wrapped_key_length);
if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL;
OEMCryptoResult result = WTPI_K2_UnwrapIntoKeyHandle(
context, wrapped_key, wrapped_key_length, key_type, &k2_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
result =
K1_CreateKeyHandle(k2_key_handle, key_type, key_size, out_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
result = KM_PairKeyHandle(*out_key_handle, k2_key_handle);
if (result != OEMCrypto_SUCCESS) {
WTPI_K2_FreeKeyHandle(k2_key_handle);
return result;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) {
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
// Free paired layer 2 key handle
WTPI_K2_SymmetricKey_Handle k2_key_handle =
KM_LookupKeyHandle(key_handle, false);
if (WTPI_K2_IsKeyHandleValid(k2_key_handle)) {
uint32_t k2_index;
result = KM_GetLayer2KeyIndex(k2_key_handle, &k2_index);
if (result != OEMCrypto_SUCCESS) return result;
UnpairKeyHandle(k2_index);
result = WTPI_K2_FreeKeyHandle(k2_key_handle);
if (result != OEMCrypto_SUCCESS) return result;
}
// Free layer 1 key
result = OPKI_FreeFromObjectTableByIndex(&key_table, key_handle->index);
free(key_handle);
return result;
}
OEMCryptoResult WTPI_C1_CopyToOutputBuffer(
const uint8_t* in, size_t size, const OPK_OutputBuffer* output_buffer,
size_t output_offset) {
size_t total_size;
if (OPK_AddOverflowUX(output_offset, size, &total_size)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (in == NULL || output_buffer == NULL || size == 0 ||
total_size > output_buffer->size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* dest = NULL;
if (output_buffer->type == OPK_SECURE_OUTPUT_BUFFER) {
OEMCryptoResult result = WTPI_GetSecureBufferAddress(
output_buffer->buffer.secure, output_offset, &dest);
if (result != OEMCrypto_SUCCESS) return result;
} else if (output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) {
dest = output_buffer->buffer.clear_insecure + output_offset;
} else {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
memmove(dest, in, size);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) {
if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,620 @@
/* 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_layer1.h"
#include <stdint.h>
#include <stdlib.h> /* THIS IS TEMPORARY UNTIL WE GET AN ALLOCATOR. */
#include <string.h>
#include "OEMCryptoCENCCommon.h"
#include "crypto_util.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_object_table.h"
#include "oemcrypto_overflow.h"
#include "openssl/rand.h"
#include "openssl/x509.h"
#include "wtpi_abort_interface.h"
#include "wtpi_config_macros.h"
#include "wtpi_device_key_access_interface.h"
#include "wtpi_device_key_interface.h"
#include "wtpi_logging_interface.h"
#include "wtpi_secure_buffer_access_interface.h"
/******************************************************************************
* This is a reference implementation of Crypto and Key Management layer 1,
* using OpenSSL/BoringSSL. The keys in this layer are encrypted and signed by a
* device specific key, and are stored in a pre-allocated table.
******************************************************************************/
/** Wrapped key data to be saved in key management layer 1 table. */
typedef struct WrappedKeyData {
uint8_t iv[KEY_IV_SIZE];
uint8_t wrapped_key[MAX_WRAPPED_SYMMETRIC_KEY_SIZE];
} WrappedKeyData;
/** Signed and wrapped key data to be saved in key management layer 1 table. */
typedef struct SignedWrappedKeyData {
uint8_t signature[SHA256_DIGEST_LENGTH];
WrappedKeyData wrapped_key_data;
} SignedWrappedKeyData;
typedef struct WTPI_K1_SymmetricKey {
SymmetricKeyType key_type;
KeySize key_size;
SignedWrappedKeyData key_data;
} WTPI_K1_SymmetricKey;
typedef struct wtpi_k1_symmetric_key_handle {
uint32_t index;
} wtpi_k1_symmetric_key_handle;
/**
* Key table used by key management layer 1. Keys in the table are wrapped by a
* device specific key. When being used, the key needs to be unwrapped and
* verified first.
*/
DEFINE_OBJECT_TABLE(key_table, WTPI_K1_SymmetricKey, MAX_NUMBER_OF_KEYS, NULL);
static bool IsKeyValid(uint32_t index) {
WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, index);
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->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256;
case ENTITLEMENT_KEY:
case MAC_KEY_SERVER:
case MAC_KEY_CLIENT:
return key->key_size == KEY_SIZE_256;
case ENCRYPTION_KEY:
case DERIVING_KEY:
return key->key_size == KEY_SIZE_128;
}
}
static bool IsKeyHandleValid(WTPI_K1_SymmetricKey_Handle key_handle) {
return (key_handle != NULL && key_handle->index < MAX_NUMBER_OF_KEYS &&
IsKeyValid(key_handle->index));
}
static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle,
SymmetricKeyType* type) {
if (key_handle == NULL || type == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, key_handle->index);
*type = key->key_type;
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, uint8_t* out_key,
KeySize out_key_size) {
ABORT_IF(out_key == NULL, "Parameters are NULL or 0");
ABORT_IF(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256,
"Invalid key size");
const uint8_t* device_key = WTPI_GetDeviceKey();
KeySize device_key_size = WTPI_GetDeviceKeySize();
uint8_t full_context[16] = {'.', '.', '.', '.', 'W', 'i', 'd', 'e',
'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'};
const size_t context_length = sizeof(full_context);
// Set the first four bytes to the specific use for this key.
memcpy(full_context, &context, 4);
const uint8_t counter = 1;
if (!OPKI_DeriveKeyWithCMAC(device_key, device_key_size, counter,
full_context, context_length, out_key_size,
out_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult EncryptAndSignKey(const uint8_t* key, size_t key_size,
uint8_t* out, size_t out_size) {
ABORT_IF(key == NULL || key_size == 0 || out == NULL,
"Parameters are NULL or 0");
ABORT_IF(out_size < sizeof(SignedWrappedKeyData),
"Invalid output buffer size");
SignedWrappedKeyData* wrapped = (SignedWrappedKeyData*)out;
/* Pick a random IV for generating keys. */
OEMCryptoResult result = WTPI_C1_RandomBytes(
wrapped->wrapped_key_data.iv, sizeof(wrapped->wrapped_key_data.iv));
if (result != OEMCrypto_SUCCESS) return result;
// Encrypt the key
uint8_t encryption_key[KEY_SIZE_128];
result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, encryption_key,
OPK_LengthToKeySize(sizeof(encryption_key)));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_AESCBCEncrypt(key, key_size, wrapped->wrapped_key_data.iv,
encryption_key, sizeof(encryption_key),
wrapped->wrapped_key_data.wrapped_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Compute the signature of the wrapped key and store it
uint8_t signing_key[KEY_SIZE_256];
result = DeriveFromDeviceKey(DEVICE_KEY_SIGN_INTERNAL_KEY, signing_key,
OPK_LengthToKeySize(sizeof(signing_key)));
if (result != OEMCrypto_SUCCESS) return result;
const uint8_t* wrapped_key_data =
(const uint8_t*)(&wrapped->wrapped_key_data);
size_t wrapped_key_data_length = sizeof(wrapped->wrapped_key_data);
if (!OPKI_HMAC_SHA256(wrapped_key_data, wrapped_key_data_length, signing_key,
sizeof(signing_key), wrapped->signature)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return result;
}
static OEMCryptoResult VerifyAndDecryptKey(
WTPI_K1_SymmetricKey_Handle key_handle, uint8_t* out_key, size_t out_size) {
ABORT_IF(!IsKeyHandleValid(key_handle), "Impossible key handle.");
ABORT_IF(out_key == NULL, "Parameters are NULL or 0");
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, key_handle->index);
if (key == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
ABORT_IF(out_size < (size_t)(key->key_size), "Invalid output buffer size");
const uint8_t* wrapped_data = (const uint8_t*)(&key->key_data);
if (wrapped_data == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const SignedWrappedKeyData* wrapped =
(const SignedWrappedKeyData*)wrapped_data;
// Verify the signature first, before decrypting
uint8_t signing_key[KEY_SIZE_256];
OEMCryptoResult result =
DeriveFromDeviceKey(DEVICE_KEY_SIGN_INTERNAL_KEY, signing_key,
OPK_LengthToKeySize(sizeof(signing_key)));
if (result != OEMCrypto_SUCCESS) return result;
const uint8_t* wrapped_key_data =
(const uint8_t*)(&wrapped->wrapped_key_data);
size_t wrapped_key_data_length = sizeof(wrapped->wrapped_key_data);
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
if (!OPKI_HMAC_SHA256(wrapped_key_data, wrapped_key_data_length, signing_key,
sizeof(signing_key), computed_signature)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (memcmp(wrapped->signature, computed_signature, SHA256_DIGEST_LENGTH) !=
0) {
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Decrypt the key
uint8_t decryption_key[KEY_SIZE_128];
result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, decryption_key,
OPK_LengthToKeySize(sizeof(decryption_key)));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_AESCBCDecrypt(wrapped->wrapped_key_data.wrapped_key,
(size_t)(key->key_size), wrapped->wrapped_key_data.iv,
decryption_key, sizeof(decryption_key), out_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle,
KeySize* size) {
if (key_handle == NULL || size == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_K1_SymmetricKey* key =
OPKI_GetFromObjectTable(&key_table, key_handle->index);
*size = key->key_size;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult AESCTRDecryptWithKeyHandle(
WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize key_size;
OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t key[KEY_SIZE_256];
result = VerifyAndDecryptKey(key_handle, key, sizeof(key));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_AESCTRDecrypt(in, in_length, iv, key, (size_t)key_size,
block_offset, out)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
/******************************************************************************
The following implement the layer 1 crypto interface.
*******************************************************************************/
OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_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 || in == NULL || in_length == 0 ||
in_length % AES_BLOCK_SIZE != 0 || iv == NULL || out == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(key_length);
if (key_size != KEY_SIZE_128 && key_length != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t decryption_key[KEY_SIZE_256];
OEMCryptoResult result =
VerifyAndDecryptKey(key_handle, decryption_key, sizeof(decryption_key));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_AESCBCDecrypt(in, in_length, iv, decryption_key, key_length, out)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize encryption_key_size;
OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &encryption_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t encryption_key[KEY_SIZE_256];
result =
VerifyAndDecryptKey(key_handle, encryption_key, sizeof(encryption_key));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_AESCBCEncrypt(in, in_length, iv, encryption_key,
(size_t)encryption_key_size, out)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_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_C1_HMAC_SHA1(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize hmac_key_size;
OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &hmac_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t hmac_key[KEY_SIZE_256];
result = VerifyAndDecryptKey(key_handle, hmac_key, sizeof(hmac_key));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_HMAC_SHA1(message, message_length, hmac_key, (size_t)hmac_key_size,
out)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize hmac_key_size;
OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &hmac_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t hmac_key[KEY_SIZE_256];
result = VerifyAndDecryptKey(key_handle, hmac_key, sizeof(hmac_key));
if (result != OEMCrypto_SUCCESS) return result;
if (!OPKI_HMAC_SHA256(message, message_length, hmac_key,
(size_t)hmac_key_size, out)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* message,
size_t message_length, const uint8_t* signature) {
if (key_handle == NULL || message == NULL || message_length == 0 ||
signature == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
OEMCryptoResult result = WTPI_C1_HMAC_SHA256(
key_handle, message, message_length, computed_signature);
if (result != OEMCrypto_SUCCESS) return result;
if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) {
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
return OEMCrypto_SUCCESS;
}
/******************************************************************************
The following implement the layer 1 key management interface.
*******************************************************************************/
OEMCryptoResult WTPI_K1_InitializeKeyManagement(void) {
OPKI_UnsafeClearObjectTable(&key_table);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_TerminateKeyManagement(void) {
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_CreateKeyHandle(
const uint8_t* serialized_bytes, size_t size, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (serialized_bytes == NULL || size == 0 || out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(size);
if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint32_t index;
WTPI_K1_SymmetricKey* key = OPKI_AllocFromObjectTable(&key_table, &index);
if (key == NULL) return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
OEMCryptoResult result =
EncryptAndSignKey(serialized_bytes, size, (uint8_t*)(&key->key_data),
sizeof(key->key_data));
if (result != OEMCrypto_SUCCESS) {
OPKI_FreeFromObjectTable(&key_table, key);
return result;
}
key->key_type = key_type;
key->key_size = key_size;
WTPI_K1_SymmetricKey_Handle handle =
malloc(sizeof(wtpi_k1_symmetric_key_handle));
if (handle == NULL) {
OPKI_FreeFromObjectTable(&key_table, key);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
handle->index = index;
*out_key_handle = handle;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle(
uint32_t context, SymmetricKeyType out_key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) {
if (out_key_handle == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
uint8_t derived_key[KEY_SIZE_256];
OEMCryptoResult result =
DeriveFromDeviceKey(context, derived_key, out_key_size);
if (result != OEMCrypto_SUCCESS) return result;
return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size,
out_key_type, out_key_handle);
}
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key,
size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (decrypt_key_handle == NULL || enc_key == NULL || enc_key_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(decrypt_key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(enc_key_length);
if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize decryption_key_size;
OEMCryptoResult result =
WTPI_K1_GetKeySize(decrypt_key_handle, &decryption_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t decryption_key[KEY_SIZE_256];
result = VerifyAndDecryptKey(decrypt_key_handle, decryption_key,
(size_t)decryption_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t key[KEY_SIZE_256];
if (!OPKI_AESCBCDecrypt(enc_key, enc_key_length, iv, decryption_key,
(size_t)decryption_key_size, key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (result != OEMCrypto_SUCCESS) return result;
return WTPI_K1_CreateKeyHandle(key, enc_key_length, key_type, out_key_handle);
}
OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys,
size_t enc_mac_keys_length, const uint8_t* iv,
WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
WTPI_K1_SymmetricKey_Handle* out_mac_key_client) {
if (decrypt_key_handle == NULL || enc_mac_keys == NULL ||
enc_mac_keys_length == 0 || out_mac_key_server == NULL ||
out_mac_key_client == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(decrypt_key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (enc_mac_keys_length != 2 * MAC_KEY_SIZE) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize decryption_key_size;
OEMCryptoResult result =
WTPI_K1_GetKeySize(decrypt_key_handle, &decryption_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t decryption_key[KEY_SIZE_256];
result = VerifyAndDecryptKey(decrypt_key_handle, decryption_key,
(size_t)decryption_key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t mac_keys[2 * MAC_KEY_SIZE];
if (!OPKI_AESCBCDecrypt(enc_mac_keys, enc_mac_keys_length, iv, decryption_key,
(size_t)decryption_key_size, mac_keys)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
result = WTPI_K1_CreateKeyHandle(mac_keys, MAC_KEY_SIZE, MAC_KEY_SERVER,
out_mac_key_server);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_K1_CreateKeyHandle(mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE,
MAC_KEY_CLIENT, out_mac_key_client);
return result;
}
OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle(
WTPI_K1_SymmetricKey_Handle key_handle, uint8_t counter,
const uint8_t* context, size_t context_length,
SymmetricKeyType out_key_type, KeySize out_key_size,
WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (key_handle == NULL || context == NULL || context_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
SymmetricKeyType key_type;
OEMCryptoResult result = GetKeyType(key_handle, &key_type);
if (result != OEMCrypto_SUCCESS || key_type != DERIVING_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize key_size;
result = WTPI_K1_GetKeySize(key_handle, &key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t key[KEY_SIZE_256];
result = VerifyAndDecryptKey(key_handle, key, (size_t)key_size);
if (result != OEMCrypto_SUCCESS) return result;
uint8_t derived_key[KEY_SIZE_256];
if (!OPKI_DeriveKeyWithCMAC(key, key_size, counter, context, context_length,
out_key_size, derived_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size,
out_key_type, out_key_handle);
}
OEMCryptoResult WTPI_K1_WrapKey(uint32_t context,
WTPI_K1_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 (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
KeySize key_size;
OEMCryptoResult result = WTPI_K1_GetKeySize(key_handle, &key_size);
if (result != OEMCrypto_SUCCESS) return result;
if (wrapped_key_length < (size_t)key_size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t key[KEY_SIZE_256];
result = VerifyAndDecryptKey(key_handle, key, (size_t)key_size);
if (result != OEMCrypto_SUCCESS) return result;
/* TODO(b/158766099): encrypt the data instead of memcpy. */
memcpy(wrapped_key, key, (size_t)key_size);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle(
uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length,
SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle) {
if (wrapped_key == NULL || wrapped_key_length == 0 ||
out_key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const KeySize key_size = OPK_LengthToKeySize(wrapped_key_length);
if (key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
/* TODO(b/158766099): decrypt the key data before creating key handle. */
return WTPI_K1_CreateKeyHandle(wrapped_key, wrapped_key_length, key_type,
out_key_handle);
}
OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) {
if (!IsKeyHandleValid(key_handle)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
result = OPKI_FreeFromObjectTableByIndex(&key_table, key_handle->index);
free(key_handle);
return result;
}
OEMCryptoResult WTPI_C1_CopyToOutputBuffer(
const uint8_t* in, size_t size, const OPK_OutputBuffer* output_buffer,
size_t output_offset) {
size_t total_size;
if (OPK_AddOverflowUX(output_offset, size, &total_size)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (in == NULL || output_buffer == NULL || size == 0 ||
total_size > output_buffer->size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* dest = NULL;
if (output_buffer->type == OPK_SECURE_OUTPUT_BUFFER) {
OEMCryptoResult result = WTPI_GetSecureBufferAddress(
output_buffer->buffer.secure, output_offset, &dest);
if (result != OEMCrypto_SUCCESS) return result;
} else if (output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) {
dest = output_buffer->buffer.clear_insecure + output_offset;
} else {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
memmove(dest, in, size);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) {
if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,275 @@
/* 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_asymmetric_interface.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "OEMCryptoCENCCommon.h"
#include "ecc_util.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_key_types.h"
#include "openssl/rsa.h"
#include "openssl/x509.h"
#include "rsa_util.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
typedef struct tee_asymmetric_key_handle {
AsymmetricKeyType key_type;
RSA* rsa_key;
EC_KEY* ecc_key;
} tee_asymmetric_key_handle;
static bool IsAsymmetricKeyHandleValid(WTPI_AsymmetricKey_Handle key_handle) {
if (key_handle == NULL) return false;
switch (key_handle->key_type) {
case DRM_RSA_PRIVATE_KEY: {
if (key_handle->rsa_key == NULL) return false;
if (key_handle->ecc_key != NULL) return false;
break;
}
case DRM_ECC_PRIVATE_KEY: {
if (key_handle->ecc_key == NULL) return false;
if (key_handle->rsa_key != NULL) return false;
break;
}
default:
return false;
}
return true;
}
static bool IsSupportedAsymmetricKeyType(AsymmetricKeyType key_type) {
return (key_type == DRM_RSA_PRIVATE_KEY || key_type == DRM_ECC_PRIVATE_KEY);
}
static bool CreateAsymmetricRSAKeyHandle(const uint8_t* serialized_bytes,
size_t size,
WTPI_AsymmetricKey_Handle handle) {
if (serialized_bytes == NULL || size == 0 || handle == NULL) {
return false;
}
RSA* rsa = NULL;
if (!DeserializePKCS8PrivateKey(serialized_bytes, size, &rsa)) {
return false;
}
if (!CheckRSAKey(rsa)) {
RSA_free(rsa);
return false;
}
handle->key_type = DRM_RSA_PRIVATE_KEY;
handle->rsa_key = rsa;
return true;
}
static bool CreateAsymmetricECCKeyHandle(const uint8_t* serialized_bytes,
size_t size,
WTPI_AsymmetricKey_Handle handle) {
EC_KEY* ecc_key = NULL;
if (!DeserializeECCPrivateKey(serialized_bytes, size, &ecc_key)) {
return false;
}
/* DeserializeECCPrivateKey will check the key after deserializing. */
handle->key_type = DRM_ECC_PRIVATE_KEY;
handle->ecc_key = ecc_key;
return true;
}
OEMCryptoResult WTPI_CreateAsymmetricKeyHandle(
const uint8_t* serialized_bytes, size_t size, AsymmetricKeyType key_type,
WTPI_AsymmetricKey_Handle* key_handle) {
if (serialized_bytes == NULL || size == 0 ||
!IsSupportedAsymmetricKeyType(key_type) || key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
WTPI_AsymmetricKey_Handle handle = malloc(sizeof(tee_asymmetric_key_handle));
if (handle == NULL) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
memset(handle, 0, sizeof(*handle));
switch (key_type) {
case DRM_RSA_PRIVATE_KEY: {
if (!CreateAsymmetricRSAKeyHandle(serialized_bytes, size, handle))
goto cleanup;
break;
}
case DRM_ECC_PRIVATE_KEY: {
if (!CreateAsymmetricECCKeyHandle(serialized_bytes, size, handle))
goto cleanup;
break;
}
}
*key_handle = handle;
return OEMCrypto_SUCCESS;
cleanup:
if (handle) {
free(handle);
}
// TODO(b/201581141): Renamed to be more applicable to both RSA and ECC keys.
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
OEMCryptoResult WTPI_FreeAsymmetricKeyHandle(
WTPI_AsymmetricKey_Handle key_handle) {
if (key_handle == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
switch (key_handle->key_type) {
case DRM_RSA_PRIVATE_KEY: {
RSA_free(key_handle->rsa_key);
key_handle->rsa_key = NULL;
break;
}
case DRM_ECC_PRIVATE_KEY: {
EC_KEY_free(key_handle->ecc_key);
key_handle->ecc_key = NULL;
break;
}
}
free(key_handle);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key_handle,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length,
RSA_Padding_Scheme padding_scheme) {
if (key_handle == NULL || message == NULL || message_length == 0 ||
signature_length == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
RSA* rsa = key_handle->rsa_key;
const size_t max_signature_size = (size_t)RSA_size(rsa);
if (signature == NULL || *signature_length < max_signature_size) {
*signature_length = max_signature_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
/* This is the standard padding scheme used for license requests. */
if (padding_scheme == kSign_RSASSA_PSS) {
size_t local_signature_length = *signature_length;
if (!RSASignSSAPSSSHA1(rsa, message, message_length, signature,
&local_signature_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*signature_length = local_signature_length;
/* This is the alternate padding scheme used by cast receivers only. */
} else if (padding_scheme == kSign_PKCS1_Block1) {
/* Pad the message with PKCS1 padding, and then encrypt. */
const int encrypt_res = RSA_private_encrypt(
message_length, message, signature, rsa, RSA_PKCS1_PADDING);
if (encrypt_res <= 0) {
dump_ssl_error();
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*signature_length = (size_t)encrypt_res;
} else { /* Bad RSA_Padding_Scheme */
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key_handle,
const uint8_t* in, size_t in_length,
uint8_t* out, size_t* out_length) {
if (key_handle == NULL || in == NULL || in_length == 0 || out == NULL ||
out_length == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
if (key_handle->key_type != DRM_RSA_PRIVATE_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
RSA* rsa = key_handle->rsa_key;
const size_t max_cleartext_size = (size_t)RSA_size(rsa);
if (*out_length < max_cleartext_size) {
*out_length = max_cleartext_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (!RSAPrivateDecrypt(rsa, in, in_length, out, out_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key_handle,
const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
if (key_handle == NULL || message == NULL || message_length == 0 ||
signature_length == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
EC_KEY* ecc_key = key_handle->ecc_key;
const size_t max_signature_size = ECDSA_size(ecc_key);
if (signature == NULL || *signature_length < max_signature_size) {
*signature_length = max_signature_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (!ECCSignECDSA(ecc_key, message, message_length, signature,
signature_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key_handle,
const uint8_t* key_source,
size_t key_source_length,
uint8_t* session_key,
size_t* session_key_length) {
if (key_handle == NULL || key_source == NULL || key_source_length == 0 ||
session_key_length == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
if (key_handle->key_type != DRM_ECC_PRIVATE_KEY) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (session_key == NULL || *session_key_length < KEY_SIZE_256) {
*session_key_length = KEY_SIZE_256;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
EC_KEY* ecc_key = key_handle->ecc_key;
if (!ECCWidevineECDHSessionKey(ecc_key, key_source, key_source_length,
session_key, session_key_length)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key_handle,
size_t* key_size) {
if (key_handle == NULL || key_size == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
ABORT_IF(!IsAsymmetricKeyHandleValid(key_handle), "Impossible key handle.");
*key_size = 0;
switch (key_handle->key_type) {
case DRM_RSA_PRIVATE_KEY:
*key_size = RSA_size(key_handle->rsa_key);
break;
case DRM_ECC_PRIVATE_KEY:
*key_size = ECDSA_size(key_handle->ecc_key);
break;
}
if (*key_size == 0) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}

View File

@@ -0,0 +1,175 @@
/* 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 "crypto_util.h"
#include <string.h>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_check_macros.h"
#include "openssl/aes.h"
#include "openssl/bio.h"
#include "openssl/cmac.h"
#include "openssl/evp.h"
#include "openssl/hmac.h"
#include "wtpi_abort_interface.h"
static bool AESEncryptBlock(const uint8_t* in, const uint8_t* key,
size_t key_size, uint8_t* out) {
ABORT_IF_NULL(in);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
AES_KEY aes_key;
AES_set_encrypt_key(key, (unsigned int)(key_size * 8), &aes_key);
AES_encrypt(in, out, &aes_key);
return true;
}
bool OPKI_AESCBCEncrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size, uint8_t* out) {
ABORT_IF_NULL(in);
ABORT_IF_ZERO(in_length);
ABORT_IF_NULL(iv);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
AES_KEY aes_key;
AES_set_encrypt_key(key, (unsigned int)(key_size * 8), &aes_key);
uint8_t iv_buffer[KEY_IV_SIZE];
memcpy(iv_buffer, iv, KEY_IV_SIZE);
AES_cbc_encrypt(in, out, in_length, &aes_key, iv_buffer, AES_ENCRYPT);
return true;
}
bool OPKI_AESCBCDecrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size, uint8_t* out) {
ABORT_IF_NULL(in);
ABORT_IF_ZERO(in_length);
ABORT_IF_NULL(iv);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
AES_KEY aes_key;
AES_set_decrypt_key(key, (unsigned int)(key_size * 8), &aes_key);
uint8_t iv_buffer[KEY_IV_SIZE];
memcpy(iv_buffer, iv, KEY_IV_SIZE);
AES_cbc_encrypt(in, out, in_length, &aes_key, iv_buffer, AES_DECRYPT);
return true;
}
bool OPKI_AESCTRDecrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size,
size_t block_offset, uint8_t* out) {
ABORT_IF_NULL(in);
ABORT_IF_ZERO(in_length);
ABORT_IF_NULL(iv);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
ABORT_IF(block_offset >= AES_BLOCK_SIZE, "Invalid block offset");
/* TODO(b/171430591): There's no reason we should reimplement part of AES-CTR
ourselves when BoringSSL can just do it for us. */
uint8_t current_iv[AES_BLOCK_SIZE];
memcpy(current_iv, &iv[0], AES_BLOCK_SIZE);
size_t l = 0;
while (l < in_length) {
uint8_t aes_output[AES_BLOCK_SIZE];
if (!AESEncryptBlock(current_iv, key, key_size, aes_output)) {
return false;
}
for (uint8_t n = block_offset; n < AES_BLOCK_SIZE && l < in_length;
++n, ++l) {
out[l] = aes_output[n] ^ in[l];
}
/* Increment the lower 8 bytes of the current_iv only. */
for (size_t n = 15; n > 7; --n) {
if (++current_iv[n] != 0) break;
}
block_offset = 0;
}
return true;
}
bool OPKI_DeriveKeyWithCMAC(const uint8_t* key, KeySize key_size,
uint8_t counter, const uint8_t* context,
size_t context_length, KeySize out_key_size,
uint8_t* out) {
ABORT_IF_NULL(key);
ABORT_IF_NULL(context);
ABORT_IF_ZERO(context_length);
ABORT_IF_NULL(out);
ABORT_IF((key_size != KEY_SIZE_128 && key_size != KEY_SIZE_256) ||
(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256),
"Invalid key size");
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
if (!cmac_ctx) return false;
for (uint8_t index = 0; index < out_key_size; index += KEY_SIZE_128) {
if (!CMAC_Init(cmac_ctx, key, key_size, cipher, 0)) {
CMAC_CTX_free(cmac_ctx);
return false;
}
if (!CMAC_Update(cmac_ctx, &counter, sizeof(counter))) {
CMAC_CTX_free(cmac_ctx);
return false;
}
counter++;
if (!CMAC_Update(cmac_ctx, context, context_length)) {
CMAC_CTX_free(cmac_ctx);
return false;
}
size_t reslen = 0;
if (!CMAC_Final(cmac_ctx, out + index, &reslen)) {
CMAC_CTX_free(cmac_ctx);
return false;
}
if (reslen != KEY_SIZE_128) {
CMAC_CTX_free(cmac_ctx);
return false;
}
}
CMAC_CTX_free(cmac_ctx);
return true;
}
bool OPKI_HMAC_SHA1(const uint8_t* message, size_t message_length,
const uint8_t* key, size_t key_size, uint8_t* out) {
ABORT_IF_NULL(message);
ABORT_IF_ZERO(message_length);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
unsigned int md_len = SHA_DIGEST_LENGTH;
if (!HMAC(EVP_sha1(), key, (size_t)key_size, message, message_length, out,
&md_len)) {
return false;
}
return true;
}
bool OPKI_HMAC_SHA256(const uint8_t* message, size_t message_length,
const uint8_t* key, size_t key_size, uint8_t* out) {
ABORT_IF_NULL(message);
ABORT_IF_ZERO(message_length);
ABORT_IF_NULL(key);
ABORT_IF_ZERO(key_size);
ABORT_IF_NULL(out);
unsigned int md_len = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), key, (size_t)key_size, message, message_length, out,
&md_len)) {
return false;
}
return true;
}

View File

@@ -0,0 +1,66 @@
/* 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_CRYPTO_UTIL_H_
#define OEMCRYPTO_TA_CRYPTO_UTIL_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "oemcrypto_key_types.h"
/**
* Encrypts |in_length| bytes of |in| using AES CBC and |iv| and places the
* result in |out|. |key_size| is the size in bytes.
* Caller retains ownership of all pointers.
*/
bool OPKI_AESCBCEncrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size, uint8_t* out);
/**
* Decrypts |in_length| bytes of |in| using AES CBC and |iv| and places the
* result in |out|. |key_size| is the size in bytes.
* Caller retains ownership of all pointers.
*/
bool OPKI_AESCBCDecrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size, uint8_t* out);
/**
* Decrypts |in_length| bytes of |in| using AES CTR and |iv| and places the
* result in |out|. |key_size| is the size in bytes.
* Caller retains ownership of all pointers.
*/
bool OPKI_AESCTRDecrypt(const uint8_t* in, size_t in_length, const uint8_t* iv,
const uint8_t* key, size_t key_size,
size_t block_offset, uint8_t* out);
/**
* Calculates a 16-byte or 32-byte CMAC authentication code using |key| and
* |context| and places the resulting key in |out|. |key_size| must be either
* KEY_SIZE_128 or KEY_SIZE_256.
* Caller retains ownership of all pointers.
*/
bool OPKI_DeriveKeyWithCMAC(const uint8_t* key, KeySize key_size,
uint8_t counter, const uint8_t* context,
size_t context_length, KeySize out_key_size,
uint8_t* out);
/**
* Calculates the HMAC of |message_length| bytes of |message| using SHA1 as the
* hash function and places the result in |out|.
* Caller retains ownership of all pointers.
*/
bool OPKI_HMAC_SHA1(const uint8_t* message, size_t message_length,
const uint8_t* key, size_t key_size, uint8_t* out);
/**
* Calculates the HMAC of |message_length| bytes of |message| using SHA256 as
* the hash function and places the result in |out|.
* Caller retains ownership of all pointers.
*/
bool OPKI_HMAC_SHA256(const uint8_t* message, size_t message_length,
const uint8_t* key, size_t key_size, uint8_t* out);
#endif /* OEMCRYPTO_TA_CRYPTO_UTIL_H_ */

View File

@@ -0,0 +1,90 @@
/* 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_crypto_asymmetric_interface.h"
#include <string.h>
#include "odk_endian.h"
#include "odk_util.h"
#include "oemcrypto_check_macros.h"
#include "oemcrypto_key_types.h"
#include "oemcrypto_overflow.h"
#include "wtpi_device_key_interface.h"
static bool IsSupportedAsymmetricKeyType(AsymmetricKeyType key_type) {
return key_type == DRM_RSA_PRIVATE_KEY || key_type == DRM_ECC_PRIVATE_KEY;
}
OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(
size_t enc_private_key_length, UNUSED AsymmetricKeyType key_type,
size_t* buffer_size) {
return WTPI_GetEncryptAndSignSize(DEVICE_KEY_WRAP_DRM_CERT,
enc_private_key_length, buffer_size);
}
static OEMCryptoResult LoadRSAKeyIntoAsymmetricKeyHandle(
const uint8_t* unwrapped_key, size_t unwrapped_key_length,
WTPI_AsymmetricKey_Handle* key_handle, uint32_t* allowed_schemes) {
size_t offset = 0;
if (unwrapped_key_length >= 8 &&
crypto_memcmp(unwrapped_key, "SIGN", 4) == 0) {
memcpy(allowed_schemes, unwrapped_key + 4, 4);
*allowed_schemes = oemcrypto_be32toh(*allowed_schemes);
offset = 8;
} else {
*allowed_schemes = kSign_RSASSA_PSS;
}
return WTPI_CreateAsymmetricKeyHandle(unwrapped_key + offset,
unwrapped_key_length - offset,
DRM_RSA_PRIVATE_KEY, key_handle);
}
static OEMCryptoResult LoadECCKeyInfoAsymmetricKeyHandle(
const uint8_t* unwrapped_key, size_t unwrapped_key_length,
WTPI_AsymmetricKey_Handle* key_handle, uint32_t* allowed_schemes) {
*allowed_schemes = 0;
return WTPI_CreateAsymmetricKeyHandle(unwrapped_key, unwrapped_key_length,
DRM_ECC_PRIVATE_KEY, key_handle);
}
OEMCryptoResult WTPI_UnwrapIntoAsymmetricKeyHandle(
const uint8_t* wrapped_key, size_t wrapped_key_length,
AsymmetricKeyType key_type, WTPI_AsymmetricKey_Handle* key_handle,
uint32_t* allowed_schemes) {
if (wrapped_key == NULL || wrapped_key_length == 0 ||
!IsSupportedAsymmetricKeyType(key_type)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
RETURN_INVALID_CONTEXT_IF_NULL(key_handle);
RETURN_INVALID_CONTEXT_IF_NULL(allowed_schemes);
/* Unwrap encrypted key. */
uint8_t unwrapped_key[PKCS8_DRM_KEY_MAX_SIZE];
size_t unwrapped_key_length = sizeof(unwrapped_key);
const OEMCryptoResult result = WTPI_VerifyAndDecrypt(
DEVICE_KEY_WRAP_DRM_CERT, wrapped_key, wrapped_key_length, unwrapped_key,
&unwrapped_key_length);
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} else if (result != OEMCrypto_SUCCESS) {
return result;
}
/* Load unwrapped key */
if (key_type == DRM_ECC_PRIVATE_KEY) {
return LoadECCKeyInfoAsymmetricKeyHandle(
unwrapped_key, unwrapped_key_length, key_handle, allowed_schemes);
}
return LoadRSAKeyIntoAsymmetricKeyHandle(unwrapped_key, unwrapped_key_length,
key_handle, allowed_schemes);
}
OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* wrapped_key,
size_t wrapped_key_length,
UNUSED AsymmetricKeyType key_type,
const uint8_t* clear_key,
size_t clear_key_length) {
return WTPI_EncryptAndSign(DEVICE_KEY_WRAP_DRM_CERT, clear_key,
clear_key_length, wrapped_key,
&wrapped_key_length);
}

View File

@@ -0,0 +1,271 @@
/* 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_decrypt_sample_interface.h"
#include <stdint.h>
#include <string.h>
#include "odk_endian.h"
#include "oemcrypto_compiler_attributes.h"
#include "oemcrypto_key_types.h"
#include "oemcrypto_math.h"
#include "oemcrypto_output.h"
#include "oemcrypto_overflow.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
#include "wtpi_secure_buffer_access_interface.h"
// Forward declaration of AESCTRDecryptWithKeyHandle
OEMCryptoResult AESCTRDecryptWithKeyHandle(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* in, size_t in_length,
const uint8_t* iv, size_t block_offset, uint8_t* out);
NO_IGNORE_RESULT static OEMCryptoResult DecryptToOutputBuffer_CBC(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* initial_iv,
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
size_t cipher_data_length, const OPK_OutputBuffer* output_buffer,
size_t output_offset) {
if (key_handle == NULL || initial_iv == NULL || pattern == NULL ||
cipher_data == NULL || cipher_data_length == 0 || output_buffer == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result =
OPK_CheckOutputBounds(output_buffer, output_offset, cipher_data_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("Output bounds check failed with result: %u", result);
return result;
}
// TODO(b/146581957): OEMCrypto v16 requires that we reject the (0, 0)
// pattern. We hope to remove this requirement in a future
// release.
if (pattern->encrypt == 0) {
LOGE("No encrypted blocks specified in pattern");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* dest = NULL;
if (output_buffer->type == OPK_SECURE_OUTPUT_BUFFER) {
result = WTPI_GetSecureBufferAddress(output_buffer->buffer.secure,
output_offset, &dest);
if (result != OEMCrypto_SUCCESS) return result;
} else if (output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) {
dest = output_buffer->buffer.clear_insecure + output_offset;
} else {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t pattern_length = pattern->encrypt + pattern->skip;
uint8_t iv[AES_BLOCK_SIZE];
uint8_t next_iv[AES_BLOCK_SIZE];
memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE);
size_t offset = 0;
while (offset < cipher_data_length) {
const size_t next_block_size =
OPK_MinUX(cipher_data_length - offset, AES_BLOCK_SIZE);
const size_t pattern_offset =
(pattern_length > 0) ? (offset / AES_BLOCK_SIZE) % pattern_length : 0;
const bool is_skip_block =
(pattern_length > 0) && (pattern_offset >= pattern->encrypt);
if (is_skip_block || (next_block_size < AES_BLOCK_SIZE)) {
memmove(&dest[offset], &cipher_data[offset], next_block_size);
} else {
uint8_t aes_output[AES_BLOCK_SIZE];
/* Save the iv for the next block, in case |cipher_data| is in the same
buffer as |dest|. */
memcpy(next_iv, &cipher_data[offset], AES_BLOCK_SIZE);
KeySize key_size;
result = WTPI_K1_GetKeySize(key_handle, &key_size);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_C1_AESCBCDecrypt(key_handle, (size_t)key_size,
&cipher_data[offset], AES_BLOCK_SIZE, iv,
aes_output);
if (result != OEMCrypto_SUCCESS) return result;
memcpy(dest + offset, aes_output, AES_BLOCK_SIZE);
memcpy(iv, next_iv, AES_BLOCK_SIZE);
}
offset += next_block_size;
}
return OEMCrypto_SUCCESS;
}
NO_IGNORE_RESULT static OEMCryptoResult DecryptToOutputBuffer_CTR(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* initial_iv,
size_t block_offset, const uint8_t* cipher_data, size_t cipher_data_length,
const OPK_OutputBuffer* output_buffer, size_t output_offset) {
if (key_handle == NULL || initial_iv == NULL ||
block_offset >= AES_BLOCK_SIZE || cipher_data == NULL ||
cipher_data_length == 0 || output_buffer == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result =
OPK_CheckOutputBounds(output_buffer, output_offset, cipher_data_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("Output bounds check failed with result: %u", result);
return result;
}
uint8_t* dest = NULL;
if (output_buffer->type == OPK_SECURE_OUTPUT_BUFFER) {
result = WTPI_GetSecureBufferAddress(output_buffer->buffer.secure,
output_offset, &dest);
if (result != OEMCrypto_SUCCESS) return result;
} else if (output_buffer->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) {
dest = output_buffer->buffer.clear_insecure + output_offset;
} else {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return AESCTRDecryptWithKeyHandle(key_handle, cipher_data, cipher_data_length,
initial_iv, block_offset, dest);
}
static OEMCryptoResult DecryptSubsample(
WTPI_K1_SymmetricKey_Handle key_handle,
const OEMCrypto_SubSampleDescription* subsample,
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
const uint8_t* iv, const OPK_OutputBuffer* output_buffer,
size_t output_offset, OEMCryptoCipherMode cipher_mode) {
if (key_handle == NULL || subsample == NULL || pattern == NULL ||
cipher_data == NULL || iv == NULL || output_buffer == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
size_t subsample_length;
if (OPK_AddOverflowUX(subsample->num_bytes_clear,
subsample->num_bytes_encrypted, &subsample_length)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
/* Handle the clear portion of the subsample. */
if (subsample->num_bytes_clear > 0) {
result = WTPI_C1_CopyToOutputBuffer(cipher_data, subsample->num_bytes_clear,
output_buffer, output_offset);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failed to copy clear data to output buffer with result: %u",
result);
return result;
}
}
/* Handle the encrypted portion of the subsample. */
if (subsample->num_bytes_encrypted > 0) {
const uint8_t* source = cipher_data + subsample->num_bytes_clear;
const size_t source_length = subsample->num_bytes_encrypted;
size_t decrypt_offset;
if (OPK_AddOverflowUX(output_offset, subsample->num_bytes_clear,
&decrypt_offset)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (cipher_mode == OEMCrypto_CipherMode_CBC) {
if (subsample->block_offset > 0 || pattern->encrypt == 0) {
LOGE(
"Invalid block offset or pattern encrypt for CBC mode, "
"block_offset "
"= %zu, encrypt = %zu",
subsample->block_offset, pattern->encrypt);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
result = DecryptToOutputBuffer_CBC(key_handle, iv, pattern, source,
source_length, output_buffer,
decrypt_offset);
} else {
if (pattern->skip != 0 || pattern->encrypt != 0) {
LOGE(
"Invalid pattern skip or encrypt for CTR mode, skip = %zu, encrypt "
"= "
"%zu",
pattern->skip, pattern->encrypt);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
result = DecryptToOutputBuffer_CTR(
key_handle, iv, subsample->block_offset, source, source_length,
output_buffer, decrypt_offset);
}
}
return result;
}
/* Advance an IV according to ISO-CENC's CTR modes. The lower half of the IV is
* split off and treated as an unsigned 64-bit integer, then incremented by the
* number of complete crypto blocks decrypted. The resulting value is then
* copied back into the IV over the previous lower half. */
UBSAN_IGNORE_UNSIGNED_OVERFLOW static void AdvanceIVandCounter(
uint8_t (*subsample_iv)[AES_BLOCK_SIZE], size_t bytes) {
static const size_t kCounterIndex = KEY_IV_SIZE / 2;
static const size_t kCounterSize = KEY_IV_SIZE / 2;
uint64_t counter;
/* Defensive copy because the elements of the array may not be properly
* aligned. */
memcpy(&counter, &(*subsample_iv)[kCounterIndex], kCounterSize);
/* The truncation here is intentional. */
const size_t increment = bytes / AES_BLOCK_SIZE;
/* The potential overflow here is intentional. */
counter = oemcrypto_htobe64(oemcrypto_be64toh(counter) + increment);
memcpy(&(*subsample_iv)[kCounterIndex], &counter, kCounterSize);
}
OEMCryptoResult WTPI_DecryptSample(
WTPI_K1_SymmetricKey_Handle key_handle,
const OEMCrypto_SampleDescription* sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const OPK_OutputBuffer* output_buffer, size_t output_offset,
OEMCryptoCipherMode cipher_mode) {
if (key_handle == NULL || sample == NULL || pattern == NULL ||
output_buffer == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
size_t starting_output_offset = output_offset;
/* Iterate through all the subsamples and decrypt each one. */
uint8_t subsample_iv[KEY_IV_SIZE];
ABORT_IF(sizeof(sample->iv) != KEY_IV_SIZE,
"The IV in OEMCrypto_SampleDescription has the wrong length.");
memcpy(subsample_iv, sample->iv, KEY_IV_SIZE);
size_t offset = 0;
for (size_t subsample_index = 0; subsample_index < sample->subsamples_length;
++subsample_index) {
const OEMCrypto_SubSampleDescription* subsample =
&(sample->subsamples[subsample_index]);
size_t subsample_length;
if (OPK_AddOverflowUX(subsample->num_bytes_clear,
subsample->num_bytes_encrypted, &subsample_length)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
size_t current_offset;
if (OPK_AddOverflowUX(starting_output_offset, offset, &current_offset)) {
LOGE("Output buffer overflow");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
result =
OPK_CheckOutputBounds(output_buffer, current_offset, subsample_length);
if (result != OEMCrypto_SUCCESS) {
LOGE("Output bounds check failed with result: %u", result);
return result;
}
const uint8_t* const subsample_source = sample->buffers.input_data + offset;
result = DecryptSubsample(key_handle, subsample, pattern, subsample_source,
subsample_iv, output_buffer, current_offset,
cipher_mode);
if (result != OEMCrypto_SUCCESS) {
LOGE("Failure %u at subsample index %zu", result, subsample_index);
return result;
}
/* Advance the offset and (if necessary) the IV. */
if (OPK_AddOverflowUX(offset, subsample_length, &offset)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (subsample->num_bytes_encrypted > 0 &&
cipher_mode == OEMCrypto_CipherMode_CTR) {
size_t distance;
if (OPK_AddOverflowUX(subsample->block_offset,
subsample->num_bytes_encrypted, &distance)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
AdvanceIVandCounter(&subsample_iv, distance);
}
} /* Subsample loop */
return result;
}

View File

@@ -0,0 +1,176 @@
/* 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_device_key_interface.h"
#include <string.h>
#include "oemcrypto_overflow.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#define UUID_LENGTH 16
// If changing the WrappedData struct family, make sure to update
// ENCRYPT_AND_SIGN_EXTRA in wtpi_config_macros.h if needed.
// This struct represents a wrapped blob that we do not yet know how to
// interpret. It contains only the fields that we expect every versioned blob to
// have.
typedef struct WrappedData {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t magic[UUID_LENGTH];
uint8_t version[sizeof(uint32_t)];
uint8_t data[];
} WrappedData;
// The randomly-generated UUID that identifies a blob as a WrappedData struct,
// in network byte order.
static const uint8_t kMagicUuid[UUID_LENGTH] = {
0xb5, 0x76, 0x3b, 0xad, 0x84, 0x05, 0x40, 0xfd,
0xa0, 0x88, 0x3b, 0x6c, 0x69, 0x97, 0xfc, 0x74};
// 1 in network byte order
static const uint8_t kVersionOne[sizeof(uint32_t)] = {0x00, 0x00, 0x00, 0x01};
// This is the layout of the |data| field of a WrappedData structure when its
// |version| field is 1.
typedef struct WrappedData_V1 {
uint8_t iv[KEY_IV_SIZE];
uint8_t enc_private_key[];
} WrappedData_V1;
OEMCryptoResult WTPI_GetEncryptAndSignSize(UNUSED uint32_t context,
size_t in_size,
size_t* wrapped_size) {
if (OPK_AddOverflowUX(in_size, sizeof(WrappedData) + sizeof(WrappedData_V1),
wrapped_size)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_EncryptAndSign(uint32_t context, const uint8_t* data,
size_t data_size, uint8_t* out,
size_t* out_size) {
if (!out_size) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
size_t needed_size;
OEMCryptoResult result =
WTPI_GetEncryptAndSignSize(context, data_size, &needed_size);
if (result != OEMCrypto_SUCCESS) return result;
if (*out_size < needed_size) {
*out_size = needed_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
// Allow querying size without these buffers.
if (!data || !out) return OEMCrypto_ERROR_INVALID_CONTEXT;
*out_size = needed_size;
WrappedData* const wrapped_header = (WrappedData*)out;
memcpy(wrapped_header->magic, kMagicUuid, sizeof(wrapped_header->magic));
memcpy(wrapped_header->version, kVersionOne, sizeof(wrapped_header->version));
WrappedData_V1* const wrapped_data = (WrappedData_V1*)wrapped_header->data;
/* Pick a random IV for generating keys. */
result = WTPI_C1_RandomBytes(wrapped_data->iv, sizeof(wrapped_data->iv));
if (result != OEMCrypto_SUCCESS) return result;
// Encrypt the buffer.
WTPI_K1_SymmetricKey_Handle encryption_key = NULL;
result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, ENCRYPTION_KEY,
&encryption_key, KEY_SIZE_128);
if (result != OEMCrypto_SUCCESS) return result;
result =
WTPI_C1_AESCBCEncrypt(encryption_key, data, data_size, wrapped_data->iv,
wrapped_data->enc_private_key);
WTPI_K1_FreeKeyHandle(encryption_key);
if (result != OEMCrypto_SUCCESS) return result;
// Compute the signature of the data past the signature block and store it
// at the start of the output buffer.
WTPI_K1_SymmetricKey_Handle signing_key = NULL;
result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, MAC_KEY_CLIENT,
&signing_key, KEY_SIZE_256);
if (result != OEMCrypto_SUCCESS) return result;
const size_t offset = sizeof(wrapped_header->signature);
result = WTPI_C1_HMAC_SHA256(signing_key, out + offset, needed_size - offset,
wrapped_header->signature);
WTPI_K1_FreeKeyHandle(signing_key);
return result;
}
static OEMCryptoResult VerifyAndDecrypt_V1(uint32_t context,
const uint8_t* data,
size_t data_size, uint8_t* out,
size_t* out_size) {
// We explicitly defer checking |out| until later, to allow querying the size
// without an out buffer.
if (data == NULL ||
data_size < sizeof(WrappedData) + sizeof(WrappedData_V1) ||
out_size == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const WrappedData* const wrapped_header = (const WrappedData*)data;
// Verify the signature first, before interpreting.
WTPI_K1_SymmetricKey_Handle signing_key = NULL;
OEMCryptoResult result = WTPI_K1_DeriveDeviceKeyIntoHandle(
context, MAC_KEY_SERVER, &signing_key, KEY_SIZE_256);
if (result != OEMCrypto_SUCCESS) return result;
const size_t offset = sizeof(wrapped_header->signature);
result =
WTPI_C1_HMAC_SHA256_Verify(signing_key, data + offset, data_size - offset,
wrapped_header->signature);
WTPI_K1_FreeKeyHandle(signing_key);
if (result != OEMCrypto_SUCCESS) return result;
// If someday we support multiple versions, we'll need to decode
// wrapped_header->version and switch our behavior depending on the version
// we find. But for now, since only version 1 is valid, we can just verify
// that wrapped_header->version is 1.
if (memcmp(wrapped_header->magic, kMagicUuid,
sizeof(wrapped_header->magic)) != 0 ||
memcmp(wrapped_header->version, kVersionOne,
sizeof(wrapped_header->version)) != 0) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const size_t needed_size =
data_size - (sizeof(WrappedData) + sizeof(WrappedData_V1));
if (*out_size < needed_size) {
*out_size = needed_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
// We defer this check to allow querying the size without an out buffer.
if (out == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
*out_size = needed_size;
const WrappedData_V1* const wrapped_data =
(const WrappedData_V1*)wrapped_header->data;
// Decrypt the buffer.
WTPI_K1_SymmetricKey_Handle encryption_key = NULL;
result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, ENCRYPTION_KEY,
&encryption_key, KEY_SIZE_128);
if (result != OEMCrypto_SUCCESS) return result;
KeySize key_size;
result = WTPI_K1_GetKeySize(encryption_key, &key_size);
if (result != OEMCrypto_SUCCESS) return result;
result = WTPI_C1_AESCBCDecrypt(encryption_key, (size_t)key_size,
wrapped_data->enc_private_key, needed_size,
wrapped_data->iv, out);
WTPI_K1_FreeKeyHandle(encryption_key);
return result;
}
OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* data,
size_t data_size, uint8_t* out,
size_t* out_size) {
// This function is broken out separately in order to ease maintenance for
// those who also need to maintain backwards-compatibility with other, older
// wrapping formats.
return VerifyAndDecrypt_V1(context, data, data_size, out, out_size);
}

View File

@@ -0,0 +1,229 @@
/* 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 "ecc_util.h"
#include <limits.h>
#include "oemcrypto_key_types.h"
#include "openssl/bio.h"
#include "openssl/ec.h"
#include "openssl/ecdsa.h"
#include "openssl/evp.h"
#include "openssl/sha.h"
#include "openssl/x509.h"
#include "rsa_util.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
/* The curve secp256r1 was originally named prime256v1 in the X9.62
specification. Renaming to match server naming conventions. */
#define NIST_P256 NID_X9_62_prime256v1 /* secp256r1 */
#define NIST_P384 NID_secp384r1
#define NIST_P521 NID_secp521r1
/* ECC DRM keys generate a 256-bit AES-CMAC key for the derivation of
other message keys. */
#define ECC_SESSION_KEY_SIZE KEY_SIZE_256
/* Returns the OpenSSL defined curve ID. Otherwise 0 is returned.
Caller may assume that any error details will be logged. */
static int GetCurveId(const EC_KEY* key) {
const EC_GROUP* group = EC_KEY_get0_group(key);
if (group == NULL) {
LOGE("EC_KEY_get0_group returned NULL");
dump_ssl_error();
return 0;
}
const int curve = EC_GROUP_get_curve_name(group);
switch (curve) {
case 0: /* No NID or error */
/* This is possible if the provided deserialized key used deprecated
curve parameters. Although it is possible that the curve parameters
are valid, keys using curve parameters should be rejected. */
LOGE("Key does not have named curve");
dump_ssl_error();
return 0;
case NIST_P256:
case NIST_P384:
case NIST_P521:
return curve;
default: /* some other curve */
LOGE("Unsupported key curve: nid = %d", curve);
return 0;
}
}
bool CheckECCKey(const EC_KEY* ecc_key) {
ABORT_IF(ecc_key == NULL, "ecc_key is NULL");
if (EC_KEY_check_key(ecc_key) == 1) return true;
LOGE("ECC key not valid");
dump_ssl_error();
return false;
}
bool DeserializeECCPrivateKey(const uint8_t* serialized_bytes, size_t size,
EC_KEY** ecc_key) {
ABORT_IF(serialized_bytes == NULL || size <= 0 || ecc_key == NULL,
"Parameters are NULL or 0");
BIO* bio = BIO_new_mem_buf(serialized_bytes, (int)size);
if (bio == NULL) {
LOGE("Failed to allocate BIO buffer");
dump_ssl_error();
return false;
}
/* Step 1: Deserializes PKCS8 PrivateKeyInfo containing an ECC key. */
PKCS8_PRIV_KEY_INFO* priv_info = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
BIO_free(bio);
bio = NULL;
if (priv_info == NULL) {
LOGE("Failed to parse private key");
dump_ssl_error();
return false;
}
/* Step 2: Convert to EC_KEY. */
EVP_PKEY* pkey = EVP_PKCS82PKEY(priv_info);
PKCS8_PRIV_KEY_INFO_free(priv_info);
priv_info = NULL;
if (pkey == NULL) {
LOGE("Failed to convert PKCS8 to EVP");
dump_ssl_error();
return false;
}
EC_KEY* key = EVP_PKEY_get1_EC_KEY(pkey);
EVP_PKEY_free(pkey);
pkey = NULL;
if (key == NULL) {
LOGE("Failed to get ECC key");
dump_ssl_error();
return false;
}
/* Step 3: Verify key parameters and curve family. */
const int check = EC_KEY_check_key(key);
if (check == 0) {
LOGE("ECC key parameters are invalid");
EC_KEY_free(key);
return false;
} else if (check == -1) {
LOGE("Failed to check ECC key");
dump_ssl_error();
EC_KEY_free(key);
return false;
}
if (GetCurveId(key) == 0) {
/* GetCurveId() will print any error logs */
EC_KEY_free(key);
return false;
}
/* Required for IETF compliance. Only required for if re-serializing. */
EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
EC_KEY_set_conv_form(key, POINT_CONVERSION_UNCOMPRESSED);
*ecc_key = key;
return true;
}
bool ECCSignECDSA(EC_KEY* ecc_key, const uint8_t* message,
size_t message_length, uint8_t* signature,
size_t* signature_length) {
ABORT_IF(ecc_key == NULL || message == NULL || message_length <= 0 ||
signature == NULL || signature_length == NULL,
"Parameters are NULL or 0");
const size_t expected_signature_length = ECDSA_size(ecc_key);
ABORT_IF(*signature_length < expected_signature_length,
"signature_length is not long enough");
ABORT_IF(*signature_length > UINT_MAX, "signature_length is too long");
/* Hash the message using the appropriate hash for the given curve.
SHA-512 is the largest hash of the expected curve. */
const int curve = GetCurveId(ecc_key);
ABORT_IF(curve == 0, "Invalid ECC key");
uint8_t hash[SHA512_DIGEST_LENGTH];
size_t hash_length = 0;
const uint8_t* hash_res = NULL;
switch (curve) {
case NIST_P256:
hash_res = SHA256(message, message_length, hash);
hash_length = SHA256_DIGEST_LENGTH;
break;
case NIST_P384:
hash_res = SHA384(message, message_length, hash);
hash_length = SHA384_DIGEST_LENGTH;
break;
case NIST_P521:
hash_res = SHA512(message, message_length, hash);
hash_length = SHA512_DIGEST_LENGTH;
break;
}
if (hash_res == NULL || hash_length == 0) {
LOGE("Failed to hash message");
dump_ssl_error();
return false;
}
/* Compute ECDSA point */
unsigned int actual_signature_length = (unsigned int)*signature_length;
if (!ECDSA_sign(/* type = DEFAULT */ 0, hash, hash_length, signature,
&actual_signature_length, ecc_key)) {
LOGE("Failed to generate signature");
dump_ssl_error();
return false;
}
*signature_length = (size_t)actual_signature_length;
return true;
}
/* This KDF function is defined by OEMCrypto ECC specification.
Function signature is based on the |kdf| parameter of
ECDH_compute_key(). This function assumes that all pointer
parameters are not null. */
static void* WidevineEccKdf(const void* secret, size_t secret_length, void* key,
size_t* key_size) {
ABORT_IF(*key_size < SHA256_DIGEST_LENGTH,
"key_size should be large enough for SHA256 digest");
if (SHA256((const uint8_t*)secret, secret_length, key) == NULL) {
dump_ssl_error();
return NULL;
}
*key_size = ECC_SESSION_KEY_SIZE;
return key;
}
bool ECCWidevineECDHSessionKey(EC_KEY* ecc_key, const uint8_t* key_source,
size_t key_source_length, uint8_t* session_key,
size_t* session_key_length) {
ABORT_IF(ecc_key == NULL || key_source == NULL || key_source_length <= 0 ||
session_key == NULL || session_key_length == NULL,
"Parameters are NULL or 0");
ABORT_IF(*session_key_length < ECC_SESSION_KEY_SIZE,
"session_key_length is not long enough");
/* First deserialize the |key_source|. */
const uint8_t* tp = key_source;
EC_KEY* public_key = d2i_EC_PUBKEY(NULL, &tp, key_source_length);
if (public_key == NULL) {
LOGE("d2i_EC_PUBKEY return NULL");
dump_ssl_error();
return false;
}
EC_KEY_set_conv_form(public_key, POINT_CONVERSION_UNCOMPRESSED);
/* Verify it is of the same curve. */
const int private_curve = GetCurveId(ecc_key);
ABORT_IF(private_curve == 0, "Invalid ECC key");
const int public_curve = GetCurveId(public_key);
if (public_curve != private_curve) {
LOGE("key_source is incompatible for ECDH: private = %d, public = %d",
private_curve, public_curve);
EC_KEY_free(public_key);
return false;
}
/* Compute ECDH using Widevine KDF. */
const int ecdh_res = ECDH_compute_key(session_key, ECC_SESSION_KEY_SIZE,
EC_KEY_get0_public_key(public_key),
ecc_key, WidevineEccKdf);
EC_KEY_free(public_key);
if (ecdh_res != ECC_SESSION_KEY_SIZE) {
LOGE("Unexpected ECDH_compute_key result: %d", ecdh_res);
dump_ssl_error();
return false;
}
*session_key_length = ECC_SESSION_KEY_SIZE;
return true;
}

View File

@@ -0,0 +1,67 @@
/* 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_ECC_UTIL_H_
#define OEMCRYPTO_TA_ECC_UTIL_H_
#include "stdbool.h"
#include "stdint.h"
#include "openssl/ec.h"
/* Checks to see that |ecc_key| is a valid ECC key. Returns false if not a
valid key.
Caller retains ownership of |ecc_key| and it must not be NULL. */
bool CheckECCKey(const EC_KEY* ecc_key);
/* Attempts to deserialize |size| bytes of |serialized_bytes| into an ECC
key and store the result in |ecc_key|.
The provided |serialized_bytes| must contain a valid ASN.1 DER encoded
PKCS8 PrivateKeyInfo containing an ECPrivateKey using named curves
(non-parameterized). Only supported curves by this API are secp256r1
(required for ECC), secp384r1 (optional) and secp521r1 (optional).
Note: If the public key is not included, then it is computed from
the private key.
Returns false if |serialized_bytes| can not be deserialized.
Caller retains ownership of all pointers and they must not be NULL. */
bool DeserializeECCPrivateKey(const uint8_t* serialized_bytes, size_t size,
EC_KEY** ecc_key);
/* Signs |message_length| bytes of |message| using |ecc_key| using ECDSA
as defined in SEC.1. The hash algorithm used depends on which curve
is used by |ecc_key|:
- SHA-256 / secp256r1 (required)
- SHA-384 / secp384r1 (optional support)
- SHA-512 / secp521r1 (optional support)
The output |signature| will be an ASN.1 DER encoded ECDSA-Sig-Value.
Returns false if the signature could not be computed.
|message_length| must be > 0 and *|signature_length| must be larger
or equal to ECDSA_size(ecc_key).
Note: It is common that the final ECDSA signature to be slightly
smaller than indicated by ECDSA_size(ecc_key), check *|signature_length|
if length has been truncated.
Caller retains ownership of all pointers and they must not be NULL. */
bool ECCSignECDSA(EC_KEY* ecc_key, const uint8_t* message,
size_t message_length, uint8_t* signature,
size_t* signature_length);
/* Derives the OEMCrypto session key used for deriving other keys.
The provided |key_source| should be the value provided to OEMCrypto
by OEMCrypto_DeriveKeysFromSessionKey().
For ECC based DRM certificates, |key_source| will be an ASN.1 DER
encoded SubjectPublicKey containing an ephemeral ECC public key
used for deriving the session key via ECDH using a Widevine-specific
Key Derivation Function (KDF). The Widevine KDF is simply a SHA-256
applied to the raw ECDH shared secret.
The output |session_key| will be an AES-256 to be used for
CMAC-AES-256 algorithm. *|session_key_length| should be at least 32
bytes.
Returns false if the provided |key_source| is not a properly encoded
ECC public key, or it belongs to a curve different than |ecc_key|.
Caller retains ownership of all pointers and they must not be NULL. */
bool ECCWidevineECDHSessionKey(EC_KEY* ecc_key, const uint8_t* key_source,
size_t key_source_length, uint8_t* session_key,
size_t* session_key_length);
#endif /* OEMCRYPTO_TA_ECC_UTIL_H_ */

View File

@@ -0,0 +1,91 @@
/* 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_KEY_MAPPING_INTERFACE_H_
#define OEMCRYPTO_TA_KEY_MAPPING_INTERFACE_H_
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_and_key_management_interface_layer2.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "oemcrypto_key_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This header file defines the interfaces for pairing/unpairing a
* WTPI_K1_SymmetricKey_Handle defined in Crypto and Key Management layer 1,
* with a WTPI_K2_SymmetricKey_Handle defined in Crypto and Key Management layer
* 2. This is used by both the REFERENCE implementation of hardware-backed
* Crypto and Key Management layer 1 (crypto_and_key_management_layer1_hw.c) and
* the TEST implementation of hardware-backed Crypto and Key Management layer 2
* (crypto_and_key_management_layer2_hw.c).
*
* Partners using the reference implementation
* crypto_and_key_management_layer1_hw.c and implementing their own
* wtpi_crypto_and_key_management_interface_layer2.h may need to implement this
* interface as well.
*/
/**
* Given a layer 1 key handle, looks up for the layer 2 key handle which is
* paired with this layer 1 key handle. Returns NULL if the key has not been
* loaded into the layer 2 key table. If this is the case and |reload_required|
* is true, it loads the key to layer 2 key table and returns the layer 2 handle
* of the loaded key.
* Also returns NULL if there is any error during look-up.
*/
WTPI_K2_SymmetricKey_Handle KM_LookupKeyHandle(
WTPI_K1_SymmetricKey_Handle k1_key_handle, bool reload_required);
/**
* Pairs a layer 1 key handle with a layer 2 key handle. Both handles eventually
* point to the same key. This allows a layer 1 function with a layer 1 key
* handle to retrieve the corresponding layer 2 key handle and then make a call
* to the layer 2 interface.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the key handles is invalid,
* and OEMCrypto_SUCCESS otherwise.
*/
OEMCryptoResult KM_PairKeyHandle(WTPI_K1_SymmetricKey_Handle k1_key_handle,
WTPI_K2_SymmetricKey_Handle k2_key_handle);
/**
* Evicts a layer 2 key in slot |k2_index|. It is also responsible for unpairing
* the handles and releasing layer 2 key handles after eviction.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if |k2_index| is invalid,
* OEMCrypto_ERROR_INSUFFICIENT_RESOURCES if no key can be evicted, and
* OEMCrypto_SUCCESS otherwise.
*/
OEMCryptoResult KM_EvictLayer2KeyByIndex(uint32_t k2_index);
/**
* Sets the key eviction handler. The handler takes a key slot to be evicted and
* returns OEMCryptoResult.
*/
void KM_SetLayer2KeyEvictionCallback(OEMCryptoResult (*callback)(uint32_t));
/**
* Returns true if |k2_index| it a valid key slot. Otherwise returns false.
*/
bool KM_IsLayer2KeyIndexValid(uint32_t k2_index);
/**
* Gets the key slot from |key_handle|, and places it in |k2_index|.
* Returns OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL or
* |key_handle| is invalid, and OEMCrypto_SUCCESS otherwise.
* Caller retains ownership of all pointers.
*/
OEMCryptoResult KM_GetLayer2KeyIndex(WTPI_K2_SymmetricKey_Handle key_handle,
uint32_t* k2_index);
#ifdef __cplusplus
}
#endif
#endif /* OEMCRYPTO_TA_KEY_MAPPING_INTERFACE_H_ */

View File

@@ -0,0 +1,145 @@
/* 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_root_of_trust_interface_layer1.h"
#include "wtpi_root_of_trust_interface_layer2.h"
#include <stddef.h>
#include <string.h>
#include "odk_endian.h"
#include "oemcrypto_key_types.h"
#include "wtpi_config_interface.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_logging_interface.h"
// This layer keeps a copy of the keybox in volatile memory. A more secure
// implementation of this would only keep the device key in memory while it is
// in use, or keep it obscured.
static WidevineKeybox gKeybox; // The current keybox.
OEMCryptoResult WTPI_InitializeKeybox(void) {
memset(&gKeybox, 0, sizeof(gKeybox));
size_t length = sizeof(gKeybox);
OEMCryptoResult result = WTPI_LoadRootOfTrust((uint8_t*)&gKeybox, &length);
if (result != OEMCrypto_SUCCESS) {
LOGD("Trouble loading the keybox: %u", result);
goto cleanup;
}
if (length == 0) {
LOGD("No keybox file loaded.");
result = OEMCrypto_ERROR_NO_DEVICE_KEY;
goto cleanup;
}
if (length != sizeof(gKeybox)) {
LOGD("That's odd. Keybox was wrong size: %zu != %zu", length,
sizeof(gKeybox));
result = OEMCrypto_ERROR_KEYBOX_INVALID;
goto cleanup;
}
cleanup:
if (result != OEMCrypto_SUCCESS) {
memset(&gKeybox, 0, sizeof(gKeybox));
}
return result;
}
OEMCryptoResult WTPI_TerminateKeybox(void) {
memset(&gKeybox, 0, sizeof(gKeybox));
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input,
size_t length) {
size_t output_length = sizeof(gKeybox);
OEMCryptoResult result;
if (length < output_length) {
result = OEMCrypto_ERROR_SHORT_BUFFER;
goto cleanup;
}
// First, try the buffer as if is a clear keybox.
memcpy(&gKeybox, input, output_length);
result = WTPI_ValidateKeybox();
if (result != OEMCrypto_SUCCESS) {
// If that didn't work, we unwrap the encrypted data that was in input, and
// store it in gKeybox.
result = WTPI_UnwrapRootOfTrust(input, length, (uint8_t*)&gKeybox,
&output_length);
if (result != OEMCrypto_SUCCESS) goto cleanup;
// Keyboxes have a fixed size. This might not be true in the future if we
// use a certificate.
if (output_length != sizeof(gKeybox)) {
result = OEMCrypto_ERROR_SHORT_BUFFER;
goto cleanup;
}
if (result != OEMCrypto_SUCCESS) goto cleanup;
// Use the layer above to validate the keybox.
result = WTPI_ValidateKeybox();
if (result != OEMCrypto_SUCCESS) goto cleanup;
}
// If the keybox was valid, then we ask the layer below us to store the keybox
// into persistent memory.
result = WTPI_SaveRootOfTrust((uint8_t*)&gKeybox, sizeof(gKeybox));
cleanup:
if (result != OEMCrypto_SUCCESS) {
WTPI_TerminateKeybox();
}
return result;
}
OEMCryptoResult WTPI_ValidateKeybox(void) {
if (memcmp(gKeybox.magic, "kbox", 4) != 0) {
return OEMCrypto_ERROR_BAD_MAGIC;
}
uint32_t crc_computed;
uint32_t crc_stored;
memcpy(&crc_stored, gKeybox.crc, sizeof(uint32_t));
crc_stored = oemcrypto_be32toh(crc_stored);
OEMCryptoResult result = WTPI_Crc32Init(&crc_computed);
if (OEMCrypto_SUCCESS != result) return result;
// Compute the CRC-32 of everything but the crc itself.
result =
WTPI_Crc32Cont((uint8_t*)&gKeybox, sizeof(gKeybox) - sizeof(uint32_t),
crc_computed, &crc_computed);
if (result != OEMCrypto_SUCCESS) return result;
if (crc_computed != crc_stored) {
LOGD("CRC Computed = %08x, stored = %08x", crc_computed, crc_stored);
return OEMCrypto_ERROR_BAD_CRC;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_GetDeviceIDFromKeybox(uint8_t* device_id,
size_t device_id_length) {
if (device_id == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (device_id_length < KEYBOX_DEVICE_ID_SIZE) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
memcpy(device_id, gKeybox.device_id, KEYBOX_DEVICE_ID_SIZE);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_GetKeyDataFromKeybox(uint8_t* key_data, size_t length) {
if (key_data == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (length != sizeof(gKeybox.data)) return OEMCrypto_ERROR_INVALID_CONTEXT;
memcpy(key_data, gKeybox.data, length);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_LoadTestKeybox(const uint8_t* test_keybox, size_t length) {
if (test_keybox == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
if (length != sizeof(gKeybox)) {
LOGD("Wrong keybox size: %zu", length);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
memcpy(&gKeybox, test_keybox, length);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult WTPI_K1_CreateKeyHandleFromKeybox(
WTPI_K1_SymmetricKey_Handle* out) {
return WTPI_K1_CreateKeyHandle(gKeybox.device_key, KEY_SIZE_128, DERIVING_KEY,
out);
}

View File

@@ -0,0 +1,135 @@
/* 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 "rsa_util.h"
#include "oemcrypto_key_types.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
#include "openssl/x509.h"
#include "wtpi_abort_interface.h"
#include "wtpi_logging_interface.h"
void dump_ssl_error(void) {
int count = 0;
unsigned long err;
while ((err = ERR_get_error())) {
count++;
char buffer[120];
ERR_error_string_n((int)err, buffer, sizeof(buffer));
LOGE("SSL Error %d -- %lu -- %s", count, err, buffer);
}
}
bool CheckRSAKey(const RSA* rsa) {
ABORT_IF(rsa == NULL, "rsa is NULL");
switch (RSA_check_key(rsa)) {
case 1: /* valid. */
return true;
case 0: /* not valid. */
LOGE("RSA key not valid");
dump_ssl_error();
return false;
default: /* -1 == check failed. */
LOGE("Error checking RSA key");
dump_ssl_error();
return false;
}
}
bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size,
RSA** rsa) {
ABORT_IF(serialized_bytes == NULL || size <= 0 || rsa == NULL,
"Parameters are NULL or 0");
BIO* bio = BIO_new_mem_buf(serialized_bytes, (int)size);
if (bio == NULL) {
LOGE("Could not allocate bio buffer");
return false;
}
bool success = false;
EVP_PKEY* evp = NULL;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL");
dump_ssl_error();
goto cleanup;
}
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("EVP_PKCS82PKEY returned NULL");
dump_ssl_error();
goto cleanup;
}
*rsa = EVP_PKEY_get1_RSA(evp);
if (*rsa == NULL) {
LOGE("PrivateKeyInfo did not contain an RSA key");
goto cleanup;
}
success = true;
cleanup:
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
return success;
}
bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length) {
ABORT_IF(rsa == NULL || message == NULL || message_length <= 0 ||
signature == NULL || signature_length == NULL,
"Parameters are NULL or 0");
size_t private_key_size = RSA_size(rsa);
ABORT_IF(*signature_length < private_key_size,
"signature_length is not long enough");
/* Hash the message using SHA1. */
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message, message_length, hash)) {
dump_ssl_error();
return false;
}
/* Add PSS padding. */
ABORT_IF(private_key_size > KEY_SIZE_3072, "rsa size is too large");
uint8_t padding[KEY_SIZE_3072];
const int kPssSaltLength = 20;
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padding, hash, EVP_sha1(),
NULL, kPssSaltLength);
if (status == 0) {
dump_ssl_error();
return false;
}
/* Encrypt PSS padded digest. */
int bytes_written = RSA_private_encrypt(private_key_size, padding, signature,
rsa, RSA_NO_PADDING);
if (bytes_written == -1) {
dump_ssl_error();
return false;
}
*signature_length = bytes_written;
return true;
}
bool RSAPrivateDecrypt(RSA* rsa, const uint8_t* in, size_t in_length,
uint8_t* out, size_t* out_length) {
ABORT_IF(rsa == NULL || in == NULL || in_length <= 0 || out == NULL ||
out_length == NULL,
"Parameters are NULL or 0");
size_t private_key_size = RSA_size(rsa);
ABORT_IF(*out_length < private_key_size, "out_length is not long enough");
int decrypted_size =
RSA_private_decrypt(in_length, in, out, rsa, RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
dump_ssl_error();
return false;
}
*out_length = decrypted_size;
return true;
}

View File

@@ -0,0 +1,45 @@
/* Copyright 2019 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_RSA_UTIL_H_
#define OEMCRYPTO_TA_RSA_UTIL_H_
#include <stdbool.h>
#include <stdint.h>
#include "openssl/rsa.h"
/* Logs any errors reported to the thread's error queue. */
void dump_ssl_error(void);
/* Checks to see that |rsa| is a valid RSA key. Returns false if |rsa| is not a
valid key.
Caller retains ownership of *|rsa| and it must not be NULL. */
bool CheckRSAKey(const RSA* rsa);
/* Attempts to deserialize |size| bytes of |serialized_bytes| into an RSA key
and store the result in |rsa|. |serialized_bytes| is expected to be a PKCS8
RSA private key. Returns false if |serialized_bytes| can not be deserialized.
|size| must be > 0.
Caller retains ownership of all pointers and they must not be NULL. */
bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size,
RSA** rsa);
/* Signs |message_length| bytes of |message| using |rsa| and padding scheme
RSASSA-PSS with SHA1 and places the result in |signature| and modifies
*|signature_length| to the appropriate value.
Returns false if the signature could not be computed.
|message_length| must be > 0 and *|signature_length| must be > RSA_size(rsa).
Caller retains ownership of all pointers and they must not be NULL. */
bool RSASignSSAPSSSHA1(RSA* rsa, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length);
/* Decrypts |in_length| bytes of |in| and places it in |out| using scheme PKCS1
OAEP and |rsa|. Modifies *|out_length| to the appropriate length.
|in_length| must be > 0 and *|out_length| must be > RSA_size(rsa).
Caller retains ownership of all pointers and they must not be NULL. */
bool RSAPrivateDecrypt(RSA* rsa, const uint8_t* in, size_t in_length,
uint8_t* out, size_t* out_length);
#endif /* OEMCRYPTO_TA_RSA_UTIL_H_ */

View File

@@ -0,0 +1,44 @@
/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
source code may only be used and distributed under the Widevine
License Agreement. */
/* The following are customizable macros we expect the TEE to implement.
These need to be in a header so the TA can use them during compilation. */
#ifndef OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_
#define OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_
/**
* Following should not be more than UINT32_MAX - 1.
*/
#define MAX_NUMBER_OF_SESSIONS 50
#define MAX_NUMBER_OF_KEYS 400
#define CONTENT_KEYS_PER_SESSION 30
#define ENTITLEMENT_KEYS_PER_SESSION 30
/** This is the number of usage entries in the header. */
#define MAX_NUMBER_OF_USAGE_ENTRIES 300
/** The number of active entries that may be loaded simultaneously. */
#define MAX_NUMBER_OF_ACTIVE_USAGE_ENTRIES 10
/** The number of active DRM keys that may be loaded simultaneously. */
#define MAX_NUMBER_OF_ASYMMETRIC_KEYS 8
/** This is the number of key slots in the layer 2 symmetric key table. */
#define MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES 8
/**
* The crypto hardware may be asked to wrap a key so that it is less vulnerable
* to attack. This is the size of a wrapped mac key.
*/
#define WRAPPED_MAC_KEY_SIZE 32
/**
* The extra size (in bytes) that is required by WTPI_EncryptAndSign. If
* supporting backwards-compatibility with multiple versions of WrappedData,
* this value should be as big as the version with the largest amount of
* overhead. */
#define ENCRYPT_AND_SIGN_EXTRA 68
#define MAX_SYMMETRIC_KEY_SIZE 32
#define MAX_WRAPPED_SYMMETRIC_KEY_SIZE MAX_SYMMETRIC_KEY_SIZE
#define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \
(PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA)
#endif /* OEMCRYPTO_TA_WTPI_CONFIG_MACROS_H_ */

View File

@@ -0,0 +1,348 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#include "GEN_common_serializer.h"
#include <string.h>
#include "GEN_common_serializer.h"
#include "bump_allocator.h"
#include "common_special_cases.h"
#include "log_macros.h"
#include "marshaller_base.h"
#include "odk_overflow.h"
#include "opk_serialization_base.h"
#include "shared_buffer_allocator.h"
#include "tos_transport_interface.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
bool SuccessResult(OEMCryptoResult result) {
switch (result) {
case OEMCrypto_SUCCESS:
case OEMCrypto_WARNING_GENERATION_SKEW:
case OEMCrypto_LOCAL_DISPLAY_ONLY:
return true;
default:
return false;
}
}
bool Is_Valid_OEMCryptoResult(uint32_t value) {
switch (value) {
case 0: /* OEMCrypto_SUCCESS */
case 1: /* OEMCrypto_ERROR_INIT_FAILED */
case 2: /* OEMCrypto_ERROR_TERMINATE_FAILED */
case 3: /* OEMCrypto_ERROR_OPEN_FAILURE */
case 4: /* OEMCrypto_ERROR_CLOSE_FAILURE */
case 5: /* OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED */
case 6: /* OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED */
case 7: /* OEMCrypto_ERROR_SHORT_BUFFER */
case 8: /* OEMCrypto_ERROR_NO_DEVICE_KEY */
case 9: /* OEMCrypto_ERROR_NO_ASSET_KEY */
case 10: /* OEMCrypto_ERROR_KEYBOX_INVALID */
case 11: /* OEMCrypto_ERROR_NO_KEYDATA */
case 12: /* OEMCrypto_ERROR_NO_CW */
case 13: /* OEMCrypto_ERROR_DECRYPT_FAILED */
case 14: /* OEMCrypto_ERROR_WRITE_KEYBOX */
case 15: /* OEMCrypto_ERROR_WRAP_KEYBOX */
case 16: /* OEMCrypto_ERROR_BAD_MAGIC */
case 17: /* OEMCrypto_ERROR_BAD_CRC */
case 18: /* OEMCrypto_ERROR_NO_DEVICEID */
case 19: /* OEMCrypto_ERROR_RNG_FAILED */
case 20: /* OEMCrypto_ERROR_RNG_NOT_SUPPORTED */
case 21: /* OEMCrypto_ERROR_SETUP */
case 22: /* OEMCrypto_ERROR_OPEN_SESSION_FAILED */
case 23: /* OEMCrypto_ERROR_CLOSE_SESSION_FAILED */
case 24: /* OEMCrypto_ERROR_INVALID_SESSION */
case 25: /* OEMCrypto_ERROR_NOT_IMPLEMENTED */
case 26: /* OEMCrypto_ERROR_NO_CONTENT_KEY */
case 27: /* OEMCrypto_ERROR_CONTROL_INVALID */
case 28: /* OEMCrypto_ERROR_UNKNOWN_FAILURE */
case 29: /* OEMCrypto_ERROR_INVALID_CONTEXT */
case 30: /* OEMCrypto_ERROR_SIGNATURE_FAILURE */
case 31: /* OEMCrypto_ERROR_TOO_MANY_SESSIONS */
case 32: /* OEMCrypto_ERROR_INVALID_NONCE */
case 33: /* OEMCrypto_ERROR_TOO_MANY_KEYS */
case 34: /* OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED */
case 35: /* OEMCrypto_ERROR_INVALID_RSA_KEY */
case 36: /* OEMCrypto_ERROR_KEY_EXPIRED */
case 37: /* OEMCrypto_ERROR_INSUFFICIENT_RESOURCES */
case 38: /* OEMCrypto_ERROR_INSUFFICIENT_HDCP */
case 39: /* OEMCrypto_ERROR_BUFFER_TOO_LARGE */
case 40: /* OEMCrypto_WARNING_GENERATION_SKEW */
case 41: /* OEMCrypto_ERROR_GENERATION_SKEW */
case 42: /* OEMCrypto_LOCAL_DISPLAY_ONLY */
case 43: /* OEMCrypto_ERROR_ANALOG_OUTPUT */
case 44: /* OEMCrypto_ERROR_WRONG_PST */
case 45: /* OEMCrypto_ERROR_WRONG_KEYS */
case 46: /* OEMCrypto_ERROR_MISSING_MASTER */
case 47: /* OEMCrypto_ERROR_LICENSE_INACTIVE */
case 48: /* OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE */
case 49: /* OEMCrypto_ERROR_ENTRY_IN_USE */
case 50: /* OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE */
case 51: /* OEMCrypto_KEY_NOT_LOADED */
case 52: /* OEMCrypto_KEY_NOT_ENTITLED */
case 53: /* OEMCrypto_ERROR_BAD_HASH */
case 54: /* OEMCrypto_ERROR_OUTPUT_TOO_LARGE */
case 55: /* OEMCrypto_ERROR_SESSION_LOST_STATE */
case 56: /* OEMCrypto_ERROR_SYSTEM_INVALIDATED */
case 57: /* OEMCrypto_ERROR_LICENSE_RELOAD */
case 58: /* OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES */
case 59: /* OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION */
case 60: /* OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION */
case 61: /* OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING */
case 65: /* OEMCrypto_ERROR_INVALID_KEY */
case 1000: /* ODK_ERROR_BASE */
case 1001: /* ODK_SET_TIMER */
case 1002: /* ODK_DISABLE_TIMER */
case 1003: /* ODK_TIMER_EXPIRED */
case 1004: /* ODK_UNSUPPORTED_API */
case 1005: /* ODK_STALE_RENEWAL */
case 2000: /* OPK_ERROR_BASE */
case 2001: /* OPK_ERROR_INCOMPATIBLE_VERSION */
case 2002: /* OPK_ERROR_NO_PERSISTENT_DATA */
return true;
default:
return false;
}
}
bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value) {
switch (value) {
case 0: /* kUnused */
case 1: /* kActive */
case 2: /* kInactive */
case 3: /* kInactiveUsed */
case 4: /* kInactiveUnused */
return true;
default:
return false;
}
}
bool Is_Valid_OEMCrypto_LicenseType(uint32_t value) {
switch (value) {
case 0: /* OEMCrypto_ContentLicense */
case 1: /* OEMCrypto_EntitlementLicense */
return true;
default:
return false;
}
}
bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value) {
switch (value) {
case 0: /* OEMCrypto_RSA_Private_Key */
case 1: /* OEMCrypto_ECC_Private_Key */
return true;
default:
return false;
}
}
bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value) {
switch (value) {
case 2011664603: /* OPK_CLEAR_INSECURE_OUTPUT_BUFFER */
case 2134605769: /* OPK_SECURE_OUTPUT_BUFFER */
return true;
default:
return false;
}
}
void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg,
OEMCrypto_Substring const* obj) {
OPK_Pack_size_t(msg, (const size_t*)&obj->offset);
OPK_Pack_size_t(msg, (const size_t*)&obj->length);
}
void OPK_Pack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject const* obj) {
OPK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id);
OPK_Pack_OEMCrypto_Substring(msg,
(const OEMCrypto_Substring*)&obj->key_data_iv);
OPK_Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_data);
OPK_Pack_OEMCrypto_Substring(
msg, (const OEMCrypto_Substring*)&obj->key_control_iv);
OPK_Pack_OEMCrypto_Substring(msg,
(const OEMCrypto_Substring*)&obj->key_control);
}
void OPK_Unpack_OEMCrypto_Substring(ODK_Message* msg,
OEMCrypto_Substring* obj) {
OPK_Unpack_size_t(msg, &obj->offset);
OPK_Unpack_size_t(msg, &obj->length);
}
void OPK_Unpack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject* obj) {
OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_id);
OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv);
OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_data);
OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control_iv);
OPK_Unpack_OEMCrypto_Substring(msg, &obj->key_control);
}
void OPK_PackNullable_uint64_t(ODK_Message* msg, const uint64_t* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_uint64_t(msg, value);
}
}
void OPK_UnpackNullable_uint64_t(ODK_Message* msg, uint64_t** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_uint64_t(msg, *value);
}
}
void OPK_UnpackAlloc_uint64_t(ODK_Message* msg, uint64_t** value) {
*value = (uint64_t*)OPK_UnpackAlloc(msg, sizeof(uint64_t));
if (*value) {
OPK_Unpack_uint64_t(msg, *value);
}
}
void OPK_PackNullable_KeySize(ODK_Message* msg, const KeySize* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_KeySize(msg, value);
}
}
void OPK_UnpackNullable_KeySize(ODK_Message* msg, KeySize** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_KeySize(msg, *value);
}
}
void OPK_UnpackAlloc_KeySize(ODK_Message* msg, KeySize** value) {
*value = (KeySize*)OPK_UnpackAlloc(msg, sizeof(KeySize));
if (*value) {
OPK_Unpack_KeySize(msg, *value);
}
}
void OPK_PackNullable_uint8_t(ODK_Message* msg, const uint8_t* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_uint8_t(msg, value);
}
}
void OPK_UnpackNullable_uint8_t(ODK_Message* msg, uint8_t** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_uint8_t(msg, *value);
}
}
void OPK_UnpackAlloc_uint8_t(ODK_Message* msg, uint8_t** value) {
*value = (uint8_t*)OPK_UnpackAlloc(msg, sizeof(uint8_t));
if (*value) {
OPK_Unpack_uint8_t(msg, *value);
}
}
void OPK_PackNullable_OPK_OutputBuffer(ODK_Message* msg,
const OPK_OutputBuffer* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_OPK_OutputBuffer(msg, value);
}
}
void OPK_UnpackNullable_OPK_OutputBuffer(ODK_Message* msg,
OPK_OutputBuffer** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_OPK_OutputBuffer(msg, *value);
}
}
void OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, const WTPI_K1_SymmetricKey_Handle* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_WTPI_K1_SymmetricKey_Handle(msg, value);
}
}
void OPK_UnpackNullable_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, *value);
}
}
void OPK_UnpackAlloc_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value) {
*value = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
if (*value) {
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, *value);
}
}
void OPK_PackNullable_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, const WTPI_AsymmetricKey_Handle* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_WTPI_AsymmetricKey_Handle(msg, value);
}
}
void OPK_UnpackNullable_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, WTPI_AsymmetricKey_Handle** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, *value);
}
}
void OPK_UnpackAlloc_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, WTPI_AsymmetricKey_Handle** value) {
*value = (WTPI_AsymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_AsymmetricKey_Handle));
if (*value) {
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, *value);
}
}
void OPK_PackNullable_uint32_t(ODK_Message* msg, const uint32_t* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_uint32_t(msg, value);
}
}
void OPK_UnpackNullable_uint32_t(ODK_Message* msg, uint32_t** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_uint32_t(msg, *value);
}
}
void OPK_UnpackAlloc_uint32_t(ODK_Message* msg, uint32_t** value) {
*value = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t));
if (*value) {
OPK_Unpack_uint32_t(msg, *value);
}
}
void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value) {
OPK_PackBoolValue(msg, value == NULL);
if (value) {
OPK_Pack_size_t(msg, value);
}
}
void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value) {
if (OPK_UnpackIsNull(msg)) {
*value = NULL;
} else {
OPK_Unpack_size_t(msg, *value);
}
}
void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value) {
*value = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t));
if (*value) {
OPK_Unpack_size_t(msg, *value);
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#ifndef OPK_COMMON_SERIALIZER_H_
#define OPK_COMMON_SERIALIZER_H_
#include "log_macros.h"
#include "opk_serialization_base.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
bool SuccessResult(OEMCryptoResult result);
bool Is_Valid_OEMCryptoResult(uint32_t value);
bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value);
bool Is_Valid_OEMCrypto_LicenseType(uint32_t value);
bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value);
bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value);
void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg,
OEMCrypto_Substring const* obj);
void OPK_Pack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject const* obj);
void OPK_Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj);
void OPK_Unpack_OEMCrypto_KeyObject(ODK_Message* msg, OEMCrypto_KeyObject* obj);
void OPK_PackNullable_uint64_t(ODK_Message* msg, const uint64_t* value);
void OPK_UnpackNullable_uint64_t(ODK_Message* msg, uint64_t** value);
void OPK_UnpackAlloc_uint64_t(ODK_Message* msg, uint64_t** value);
void OPK_PackNullable_KeySize(ODK_Message* msg, const KeySize* value);
void OPK_UnpackNullable_KeySize(ODK_Message* msg, KeySize** value);
void OPK_UnpackAlloc_KeySize(ODK_Message* msg, KeySize** value);
void OPK_PackNullable_uint8_t(ODK_Message* msg, const uint8_t* value);
void OPK_UnpackNullable_uint8_t(ODK_Message* msg, uint8_t** value);
void OPK_UnpackAlloc_uint8_t(ODK_Message* msg, uint8_t** value);
void OPK_PackNullable_OPK_OutputBuffer(ODK_Message* msg,
const OPK_OutputBuffer* value);
void OPK_UnpackNullable_OPK_OutputBuffer(ODK_Message* msg,
OPK_OutputBuffer** value);
void OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, const WTPI_K1_SymmetricKey_Handle* value);
void OPK_UnpackNullable_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value);
void OPK_UnpackAlloc_WTPI_K1_SymmetricKey_Handle(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle** value);
void OPK_PackNullable_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, const WTPI_AsymmetricKey_Handle* value);
void OPK_UnpackNullable_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, WTPI_AsymmetricKey_Handle** value);
void OPK_UnpackAlloc_WTPI_AsymmetricKey_Handle(
ODK_Message* msg, WTPI_AsymmetricKey_Handle** value);
void OPK_PackNullable_uint32_t(ODK_Message* msg, const uint32_t* value);
void OPK_UnpackNullable_uint32_t(ODK_Message* msg, uint32_t** value);
void OPK_UnpackAlloc_uint32_t(ODK_Message* msg, uint32_t** value);
void OPK_PackNullable_size_t(ODK_Message* msg, const size_t* value);
void OPK_UnpackNullable_size_t(ODK_Message* msg, size_t** value);
void OPK_UnpackAlloc_size_t(ODK_Message* msg, size_t** value);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPK_COMMON_SERIALIZER_H_ */

View File

@@ -0,0 +1,195 @@
/*
* 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 "common_special_cases.h"
#include "log_macros.h"
#include "opk_serialization_base.h"
void OPK_Pack_WTPI_K1_SymmetricKey_Handle(
ODK_Message* message, const WTPI_K1_SymmetricKey_Handle* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_size_t(message, (const size_t*)value);
}
void OPK_Pack_WTPI_AsymmetricKey_Handle(
ODK_Message* message, const WTPI_AsymmetricKey_Handle* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_size_t(message, (const size_t*)value);
}
void OPK_Unpack_WTPI_K1_SymmetricKey_Handle(
ODK_Message* message, WTPI_K1_SymmetricKey_Handle* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_size_t(message, (size_t*)value);
}
void OPK_Unpack_WTPI_AsymmetricKey_Handle(ODK_Message* message,
WTPI_AsymmetricKey_Handle* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_size_t(message, (size_t*)value);
}
void OPK_Pack_OPK_OutputBuffer(ODK_Message* message,
const OPK_OutputBuffer* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_uint32_t(message, (const uint32_t*)&value->type);
OPK_Pack_size_t(message, &value->size);
switch (value->type) {
case OPK_CLEAR_INSECURE_OUTPUT_BUFFER:
OPK_PackSharedBuffer(message, value->buffer.clear_insecure,
OPK_ToLengthType(value->size),
/* map */ true, /* copy in */ true,
/* is_output */ true);
break;
case OPK_SECURE_OUTPUT_BUFFER:
// TODO: actually implement
break;
default:
break;
}
}
void OPK_Unpack_OPK_OutputBuffer(ODK_Message* message,
OPK_OutputBuffer* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_uint32_t(message, (uint32_t*)&value->type);
OPK_Unpack_size_t(message, &value->size);
switch (value->type) {
case OPK_CLEAR_INSECURE_OUTPUT_BUFFER:
OPK_UnpackSharedBuffer(message, &value->buffer.clear_insecure,
OPK_ToLengthType(value->size),
/* map */ true, /* is output */ true);
break;
case OPK_SECURE_OUTPUT_BUFFER:
// TODO: actually implement
break;
default:
break;
}
}
void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc(
ODK_Message* message, const OEMCrypto_CENCEncryptPatternDesc* value) {}
void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc(
ODK_Message* message, OEMCrypto_CENCEncryptPatternDesc* value) {}
void OPK_Pack_SymmetricKeyType(ODK_Message* message,
const SymmetricKeyType* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_uint32_t(message, (const uint32_t*)value);
}
void OPK_Unpack_SymmetricKeyType(ODK_Message* message,
SymmetricKeyType* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_uint32_t(message, (uint32_t*)value);
}
void OPK_Pack_AsymmetricKeyType(ODK_Message* message,
const AsymmetricKeyType* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_uint32_t(message, (const uint32_t*)value);
}
void OPK_Unpack_AsymmetricKeyType(ODK_Message* message,
AsymmetricKeyType* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_uint32_t(message, (uint32_t*)value);
}
void OPK_Pack_RSA_Padding_Scheme(ODK_Message* message,
const RSA_Padding_Scheme* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_uint8_t(message, (const uint8_t*)value);
}
void OPK_Unpack_RSA_Padding_Scheme(ODK_Message* message,
RSA_Padding_Scheme* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_uint8_t(message, (uint8_t*)value);
}
void OPK_Pack_KeySize(ODK_Message* message, const KeySize* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Pack_size_t(message, (const size_t*)value);
}
void OPK_Unpack_KeySize(ODK_Message* message, KeySize* value) {
if (value == NULL) {
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
return;
}
OPK_Unpack_size_t(message, (size_t*)value);
}
void OPK_Pack_OEMCrypto_SharedMemory(ODK_Message* message,
const OEMCrypto_SharedMemory* value) {
(void)message;
(void)value;
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
}
void OPK_Unpack_OEMCrypto_SharedMemory(ODK_Message* message,
OEMCrypto_SharedMemory* value) {
(void)message;
(void)value;
ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2020 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_COMMON_SPECIAL_CASES_H_
#define WTPI_TEST_COMMON_SPECIAL_CASES_H_
#include "odk_message.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
void OPK_Pack_WTPI_K1_SymmetricKey_Handle(
ODK_Message* message, const WTPI_K1_SymmetricKey_Handle* value);
void OPK_Unpack_WTPI_K1_SymmetricKey_Handle(ODK_Message* message,
WTPI_K1_SymmetricKey_Handle* value);
void OPK_Pack_WTPI_AsymmetricKey_Handle(ODK_Message* message,
const WTPI_AsymmetricKey_Handle* value);
void OPK_Unpack_WTPI_AsymmetricKey_Handle(ODK_Message* message,
WTPI_AsymmetricKey_Handle* value);
void OPK_Pack_OPK_OutputBuffer(ODK_Message* message,
const OPK_OutputBuffer* value);
void OPK_Unpack_OPK_OutputBuffer(ODK_Message* message, OPK_OutputBuffer* value);
void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc(
ODK_Message* message, const OEMCrypto_CENCEncryptPatternDesc* value);
void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc(
ODK_Message* message, OEMCrypto_CENCEncryptPatternDesc* value);
void OPK_Pack_SymmetricKeyType(ODK_Message* msg,
const SymmetricKeyType* key_type);
void OPK_Unpack_SymmetricKeyType(ODK_Message* msg, SymmetricKeyType* key_type);
void OPK_Pack_AsymmetricKeyType(ODK_Message* msg,
const AsymmetricKeyType* key_type);
void OPK_Unpack_AsymmetricKeyType(ODK_Message* msg,
AsymmetricKeyType* key_type);
void OPK_Pack_RSA_Padding_Scheme(ODK_Message* msg,
const RSA_Padding_Scheme* padding_scheme);
void OPK_Unpack_RSA_Padding_Scheme(ODK_Message* msg,
RSA_Padding_Scheme* padding_scheme);
void OPK_Pack_KeySize(ODK_Message* msg, const KeySize* key_size);
void OPK_Unpack_KeySize(ODK_Message* msg, KeySize* key_size);
void OPK_Pack_OEMCrypto_SharedMemory(ODK_Message* message,
const OEMCrypto_SharedMemory* value);
void OPK_Unpack_OEMCrypto_SharedMemory(ODK_Message* message,
OEMCrypto_SharedMemory* value);
#endif

View File

@@ -0,0 +1,867 @@
// 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 <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "opk_init.h"
#include "tos_shared_memory_interface.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
#define TEST_RSA_KEY_DER_LEN 1216
#define HELLO_WORLD_ENC_LEN 256
extern uint8_t test_rsa_key_der[TEST_RSA_KEY_DER_LEN];
extern uint8_t hello_world_encrypted[HELLO_WORLD_ENC_LEN];
class CryptoTest : public ::testing::Test {
protected:
CryptoTest() {}
void SetUp() override {
::testing::Test::SetUp();
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
OPK_Initialize();
}
void TearDown() override {
OPK_Terminate();
::testing::Test::TearDown();
}
};
TEST_F(CryptoTest, CreateKeyHandleWorksWithTypicalKeySize) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, &key_handle));
ASSERT_NE(nullptr, key_handle);
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, CONTENT_KEY, &key_handle));
ASSERT_NE(nullptr, key_handle);
}
TEST_F(CryptoTest, CreateKeyHandleFailsWithBadParams) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_CreateKeyHandle(key, UNKNOWN_KEY_SIZE, CONTENT_KEY, &key_handle));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_CreateKeyHandle(NULL, KEY_SIZE_128, CONTENT_KEY, &key_handle));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, NULL));
}
TEST_F(CryptoTest, AESCBCEncryptHelloWorld) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
SymmetricKeyType key_type = CONTENT_KEY;
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle));
ASSERT_NE(nullptr, key_handle);
// Encrypt
std::string message = "Hello world!______";
std::vector<uint8_t> input(message.begin(), message.end());
std::vector<uint8_t> iv = {99, 0, 23, 18, 75, 4, 92, 115,
24, 70, 56, 57, 12, 43, 15, 29};
std::vector<uint8_t> output(16, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, iv.data(),
output.data()));
std::vector<uint8_t> expected = {72, 148, 193, 81, 175, 242, 38, 26,
247, 167, 88, 96, 223, 94, 41, 95};
for (int i = 0; i < 16; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, AESCBCEncryptFailsForBadInput) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
SymmetricKeyType key_type = CONTENT_KEY;
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle));
std::string message = "Hello world!______";
std::vector<uint8_t> input(message.begin(), message.end());
std::vector<uint8_t> iv = {99, 0, 23, 18, 75, 4, 92, 115,
24, 70, 56, 57, 12, 43, 15, 29};
std::vector<uint8_t> output(16, 0);
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCEncrypt(NULL, input.data(), 16, iv.data(), output.data()));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCEncrypt(key_handle, NULL, 16, iv.data(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 0, iv.data(),
output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 15, iv.data(),
output.data()));
// TODO(b/205751866): serializer allocates iv array on TEE side regardless if
// REE iv ptr is NULL, so the NULL never propagates to the TEE
//
// ASSERT_EQ(
// OEMCrypto_ERROR_INVALID_CONTEXT,
// WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, NULL, output.data()));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, iv.data(), NULL));
}
TEST_F(CryptoTest, AESCBCDecryptHelloWorld) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
SymmetricKeyType key_type = CONTENT_KEY;
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle));
ASSERT_NE(nullptr, key_handle);
// Decrypt
// Uses encrypted "hello world" input from the Encrypt test, same IV
std::vector<uint8_t> input = {72, 148, 193, 81, 175, 242, 38, 26,
247, 167, 88, 96, 223, 94, 41, 95};
std::vector<uint8_t> iv = {99, 0, 23, 18, 75, 4, 92, 115,
24, 70, 56, 57, 12, 43, 15, 29};
std::vector<uint8_t> output(16, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16,
iv.data(), output.data()));
std::string hello_world = "Hello world!_____";
std::vector<uint8_t> expected(hello_world.begin(), hello_world.end());
for (int i = 0; i < 16; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, AESCBCEncryptDecryptLoop) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, &key_handle));
ASSERT_NE(nullptr, key_handle);
std::string message = "EncryptDecryptLoop";
std::vector<uint8_t> input(message.begin(), message.end());
std::vector<uint8_t> iv = {99, 0, 23, 18, 75, 4, 92, 115,
24, 70, 56, 57, 12, 43, 15, 29};
std::vector<uint8_t> decrypted(16, 0);
for (int i = 0; i < 10; i++) {
std::vector<uint8_t> encrypted(16, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_AESCBCEncrypt(key_handle, input.data(), 16, iv.data(),
encrypted.data()));
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, encrypted.data(),
16, iv.data(), decrypted.data()));
}
for (int i = 0; i < 16; i++) {
ASSERT_EQ(input[i], decrypted[i]);
}
}
TEST_F(CryptoTest, AESCBCDecryptFailsForBadInput) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
SymmetricKeyType key_type = CONTENT_KEY;
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle));
std::vector<uint8_t> input = {72, 148, 193, 81, 175, 242, 38, 26,
247, 167, 88, 96, 223, 94, 41, 95};
std::vector<uint8_t> iv = {99, 0, 23, 18, 75, 4, 92, 115,
24, 70, 56, 57, 12, 43, 15, 29};
std::vector<uint8_t> output(16, 0);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCDecrypt(NULL, KEY_SIZE_128, input.data(), 16,
iv.data(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, NULL, 16, iv.data(),
output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 0,
iv.data(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 15,
iv.data(), output.data()));
// TODO(b/205751866): serializer allocates iv array on TEE side regardless if
// REE iv ptr is NULL, so the NULL never propagates to the TEE
//
// ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
// WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16, NULL,
// output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_AESCBCDecrypt(key_handle, KEY_SIZE_128, input.data(), 16,
iv.data(), NULL));
}
// TODO: larger inputs for encrypt/decrypt?
TEST_F(CryptoTest, SHA256Basic) {
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_SHA256(input.data(), input.size(), output.data()));
std::vector<uint8_t> expected = {99, 13, 205, 41, 102, 196, 51, 102,
145, 18, 84, 72, 187, 178, 91, 79,
244, 18, 164, 156, 115, 45, 178, 200,
171, 193, 184, 88, 27, 215, 16, 221};
for (int i = 0; i < 32; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, SHA256Small) {
std::vector<uint8_t> input;
for (int i = 0; i < 16; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_SHA256(input.data(), input.size(), output.data()));
std::vector<uint8_t> expected = {190, 69, 203, 38, 5, 191, 54, 190,
189, 230, 132, 132, 26, 40, 240, 253,
67, 198, 152, 80, 163, 220, 229, 254,
219, 166, 153, 40, 238, 58, 137, 145};
for (int i = 0; i < 32; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, SHA256FailsWithBadInput) {
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_SHA256(NULL, input.size(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_SHA256(input.data(), 0, output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_SHA256(input.data(), input.size(), NULL));
}
TEST_F(CryptoTest, SHA256Medium) {
std::vector<uint8_t> input;
for (int i = 0; i < 1024; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_SHA256(input.data(), input.size(), output.data()));
std::vector<uint8_t> expected = {120, 91, 7, 81, 252, 44, 83, 220,
20, 164, 206, 61, 128, 14, 105, 239,
156, 225, 0, 158, 179, 39, 204, 244,
88, 175, 224, 156, 36, 44, 38, 201};
for (int i = 0; i < 32; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, CRC32FailsWhenInitialIsNull) {
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_Crc32Init(NULL));
}
TEST_F(CryptoTest, CRC32Basic) {
uint32_t initial_hash;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_Crc32Init(&initial_hash));
std::vector<uint8_t> input;
for (int i = 0; i < 128; i++) {
input.push_back(i);
}
uint32_t old_crc = initial_hash;
uint32_t new_crc;
uint32_t expected = 0x2f18b043;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_Crc32Cont(input.data(), input.size(), old_crc, &new_crc));
ASSERT_EQ(expected, new_crc);
}
TEST_F(CryptoTest, CRC32ContFailsForBadInputs) {
uint32_t initial_hash;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_Crc32Init(&initial_hash));
std::vector<uint8_t> input;
for (int i = 0; i < 128; i++) {
input.push_back(i);
}
uint32_t old_crc = initial_hash;
uint32_t new_crc;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont(NULL, input.size(), old_crc, &new_crc));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont(input.data(), 0, old_crc, &new_crc));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont(input.data(), input.size(), old_crc, NULL));
}
TEST_F(CryptoTest, Crc32Cont_OutputBufferBasic) {
std::vector<uint8_t> buf;
for (int i = 0; i < 32; i++) {
buf.push_back(i);
}
OPK_OutputBuffer in;
in.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
in.buffer.clear_insecure = buf.data();
in.size = buf.size();
uint32_t new_crc;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_Crc32Cont_OutputBuffer(&in, 0, 32, 0, &new_crc));
ASSERT_EQ((uint32_t)0xc5d43637, new_crc);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_Crc32Cont_OutputBuffer(&in, 2, 30, 0, &new_crc));
ASSERT_EQ((uint32_t)0xe45a3a4f, new_crc);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_Crc32Cont_OutputBuffer(&in, 0, 30, 0, &new_crc));
ASSERT_EQ((uint32_t)0x8cb03e9b, new_crc);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_Crc32Cont_OutputBuffer(&in, 0, 32, 0x4242ff90, &new_crc));
ASSERT_EQ((uint32_t)0x088147d2, new_crc);
}
TEST_F(CryptoTest, Crc32Cont_OutputBufferFailsWithBadInput) {
std::vector<uint8_t> buf;
for (int i = 0; i < 32; i++) {
buf.push_back(i);
}
OPK_OutputBuffer in;
in.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
in.buffer.clear_insecure = buf.data();
in.size = buf.size();
uint32_t new_crc;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont_OutputBuffer(NULL, 0, 32, 0, &new_crc));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont_OutputBuffer(&in, 30, 32, 0, &new_crc));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_Crc32Cont_OutputBuffer(&in, 0, 32, 0, NULL));
}
TEST_F(CryptoTest, HMAC_SHA256FailsWithBadInput) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256(NULL, input.data(), input.size(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256(key_handle, NULL, input.size(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256(key_handle, input.data(), 0, output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), NULL));
}
TEST_F(CryptoTest, HMAC_SHA256Basic) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(32, 0);
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(),
output.data()));
std::vector<uint8_t> expected = {232, 73, 155, 228, 241, 152, 13, 104,
241, 50, 34, 164, 24, 223, 92, 189,
151, 213, 63, 221, 245, 144, 194, 16,
142, 34, 212, 0, 5, 183, 7, 19};
for (int i = 0; i < 32; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, HMAC_SHA256_VerifyBasic) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> signature = {232, 73, 155, 228, 241, 152, 13, 104,
241, 50, 34, 164, 24, 223, 92, 189,
151, 213, 63, 221, 245, 144, 194, 16,
142, 34, 212, 0, 5, 183, 7, 19};
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 32,
signature.data()));
signature[0] = 0xFF;
ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(),
signature.data()));
}
TEST_F(CryptoTest, HMAC_SHA256_VerifyFailsWithBadInput) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> signature = {70, 189, 50, 6, 5, 197, 166, 182,
22, 58, 183, 11, 198, 52, 91, 146,
165, 249, 8, 231, 159, 229, 137, 121,
194, 62, 187, 71, 209, 165, 227, 7};
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256_Verify(NULL, input.data(), input.size(),
signature.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256_Verify(key_handle, NULL, input.size(),
signature.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 0,
signature.data()));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(), NULL));
}
TEST_F(CryptoTest, HMAC_SHA1Basic) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(20, 0);
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(key_handle, input.data(),
input.size(), output.data()));
std::vector<uint8_t> expected = {106, 229, 208, 106, 97, 2, 39,
252, 78, 167, 85, 132, 70, 103,
130, 238, 157, 20, 201, 141};
for (int i = 0; i < 20; i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, HMAC_SHA1FailsWithBadInput) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle));
std::vector<uint8_t> input;
for (int i = 0; i < 32; i++) {
input.push_back(i);
}
std::vector<uint8_t> output(20, 0);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA1(NULL, input.data(), input.size(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA1(key_handle, NULL, input.size(), output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA1(key_handle, input.data(), 0, output.data()));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_HMAC_SHA1(key_handle, input.data(), input.size(), NULL));
}
TEST_F(CryptoTest, CopyToOutputBufferBasicInsecure) {
std::vector<uint8_t> input(32, 0);
for (int i = 0; i < 32; i++) {
input[i] = i;
}
std::vector<uint8_t> output(16, 0);
OPK_OutputBuffer output_buffer;
output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
output_buffer.buffer.clear_insecure = output.data();
output_buffer.size = 16;
size_t offset = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_CopyToOutputBuffer(
input.data(), 10, &output_buffer, offset));
for (int i = 0; i < 10; i++) {
ASSERT_EQ(input[i], output[i]);
}
}
TEST_F(CryptoTest, CopyToOutputBufferBasicInsecureWithOffset) {
std::vector<uint8_t> input(32, 0);
for (int i = 0; i < 32; i++) {
input[i] = i;
}
std::vector<uint8_t> output(16, 0);
OPK_OutputBuffer output_buffer;
output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
output_buffer.buffer.clear_insecure = output.data();
output_buffer.size = 16;
size_t offset = 5;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_CopyToOutputBuffer(
input.data(), 10, &output_buffer, offset));
for (int i = 0; i < 5; i++) {
ASSERT_EQ(0, output[i]);
}
for (int i = 0; i < 10; i++) {
ASSERT_EQ(input[i], output[i + offset]);
}
}
TEST_F(CryptoTest, CopyToOutputBufferBasicInsecureOverlap) {
std::vector<uint8_t> input(32, 0);
for (int i = 0; i < 32; i++) {
input[i] = i;
}
OPK_OutputBuffer output_buffer;
output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
output_buffer.buffer.clear_insecure = input.data();
output_buffer.size = 16;
size_t offset = 5;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_CopyToOutputBuffer(
input.data(), 10, &output_buffer, offset));
for (int i = 0; i < 5; i++) {
ASSERT_EQ(i, input[i]);
}
for (int i = 0; i < 10; i++) {
ASSERT_EQ(i, input[i + offset]);
}
}
TEST_F(CryptoTest, CopyToOutputBufferFailsWithBadInput) {
std::vector<uint8_t> input(32, 0);
for (int i = 0; i < 32; i++) {
input[i] = i;
}
OPK_OutputBuffer output_buffer;
output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER;
output_buffer.buffer.clear_insecure = input.data();
output_buffer.size = 16;
size_t offset = 5;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_CopyToOutputBuffer(NULL, 10, &output_buffer, offset));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_CopyToOutputBuffer(input.data(), 0, &output_buffer, offset));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_CopyToOutputBuffer(input.data(), 10, NULL, offset));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_CopyToOutputBuffer(input.data(), 32, &output_buffer, offset));
}
TEST_F(CryptoTest, CreateAsymmetricKeyHandle) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
ASSERT_NE(nullptr, handle);
}
TEST_F(CryptoTest, CreateAsymmetricKeyHandleFailsForBadInput) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_CreateAsymmetricKeyHandle(NULL, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_CreateAsymmetricKeyHandle(test_rsa_key_der, 0,
DRM_RSA_PRIVATE_KEY, &handle));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_CreateAsymmetricKeyHandle(test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, NULL));
const uint8_t bad_format[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
ASSERT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY,
WTPI_CreateAsymmetricKeyHandle(bad_format, 32, DRM_RSA_PRIVATE_KEY,
&handle));
}
TEST_F(CryptoTest, RSASign) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
std::string message = "Hello world";
std::vector<uint8_t> input(message.begin(), message.end());
std::vector<uint8_t> output(256, 0);
size_t output_len = 256;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_RSASign(handle, input.data(), input.size(), output.data(),
&output_len, kSign_RSASSA_PSS));
// TODO: verify RSA signature
}
TEST_F(CryptoTest, RSASignFailsWithBadInput) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
std::string message = "Hello world";
std::vector<uint8_t> input(message.begin(), message.end());
std::vector<uint8_t> output(256, 0);
size_t output_len = 256;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSASign(NULL, input.data(), input.size(), output.data(),
&output_len, kSign_RSASSA_PSS));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSASign(handle, NULL, input.size(), output.data(), &output_len,
kSign_RSASSA_PSS));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSASign(handle, input.data(), 0, output.data(), &output_len,
kSign_RSASSA_PSS));
// wtpi_crypto_asymmetric_interface.h specifically mentions that it is okay
// for the |signature| field to be NULL
//
// ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
// WTPI_RSASign(handle, input.data(), input.size(), NULL,
// &output_len, kSign_RSASSA_PSS));
output_len = 10;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
WTPI_RSASign(handle, input.data(), input.size(), output.data(),
&output_len, kSign_RSASSA_PSS));
}
TEST_F(CryptoTest, RSADecrypt) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
std::vector<uint8_t> output(256, 0);
size_t output_len = 256;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_RSADecrypt(handle, hello_world_encrypted, HELLO_WORLD_ENC_LEN,
output.data(), &output_len));
std::string message = "Hello world!";
std::vector<uint8_t> expected(message.begin(), message.end());
for (size_t i = 0; i < expected.size(); i++) {
ASSERT_EQ(expected[i], output[i]);
}
}
TEST_F(CryptoTest, RSADecryptFailsForBadInput) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
std::vector<uint8_t> output(256, 0);
size_t output_len = 256;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSADecrypt(NULL, hello_world_encrypted, HELLO_WORLD_ENC_LEN,
output.data(), &output_len));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSADecrypt(handle, NULL, HELLO_WORLD_ENC_LEN, output.data(),
&output_len));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSADecrypt(handle, hello_world_encrypted, 0, output.data(),
&output_len));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_RSADecrypt(handle, hello_world_encrypted, HELLO_WORLD_ENC_LEN,
NULL, &output_len));
output_len = 10;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
WTPI_RSADecrypt(handle, hello_world_encrypted, HELLO_WORLD_ENC_LEN,
output.data(), &output_len));
ASSERT_EQ((uint32_t)256, output_len);
}
TEST_F(CryptoTest, GetSignatureSize) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
size_t signature_size = 0;
size_t expected_size = 256;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_GetSignatureSize(handle, &signature_size));
ASSERT_EQ(expected_size, signature_size);
}
TEST_F(CryptoTest, GetSignatureSizeFailsForBadInputs) {
WTPI_AsymmetricKey_Handle handle;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle(
test_rsa_key_der, TEST_RSA_KEY_DER_LEN,
DRM_RSA_PRIVATE_KEY, &handle));
size_t signature_size = 0;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_GetSignatureSize(NULL, &signature_size));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_GetSignatureSize(handle, NULL));
}
// TODO(b/205752860): wtpi_crypto_and_key_management_interface_layer1.h does not
// actually specify what should happen for NULL/0 inputs to RandomBytes()
TEST_F(CryptoTest, DISABLED_RandomBytesFailsForBadInputs) {
std::vector<uint8_t> out(32, 0);
size_t size = 32;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_C1_RandomBytes(NULL, size));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_C1_RandomBytes(out.data(), 0));
}
TEST_F(CryptoTest, DeriveKeyFromKeyHandleFailsForBadInputs) {
const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
WTPI_K1_SymmetricKey_Handle key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, DERIVING_KEY, &key_handle));
uint8_t counter = 0;
const uint8_t context[] = {50, 51, 52, 53};
size_t context_length = 4;
SymmetricKeyType out_key_type = CONTENT_KEY;
KeySize out_key_size = KEY_SIZE_128;
WTPI_K1_SymmetricKey_Handle out;
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_DeriveKeyFromKeyHandle(NULL, counter, context, context_length,
out_key_type, out_key_size, &out));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_DeriveKeyFromKeyHandle(key_handle, counter, NULL, context_length,
out_key_type, out_key_size, &out));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_DeriveKeyFromKeyHandle(key_handle, counter, context, 0,
out_key_type, out_key_size, &out));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
WTPI_K1_DeriveKeyFromKeyHandle(key_handle, counter, context,
context_length, out_key_type,
out_key_size, NULL));
}
// TODO: DeriveKeyFromKeyHandle with expected CMAC+counter construction output

View File

@@ -0,0 +1,54 @@
// 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 <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "opk_init.h"
#include "wtpi_generation_number_interface.h"
class GenerationNumberInterfaceTest : public ::testing::Test {
protected:
GenerationNumberInterfaceTest() {}
void SetUp() override {
::testing::Test::SetUp();
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
OPK_Initialize();
}
void TearDown() override {
OPK_Terminate();
::testing::Test::TearDown();
}
};
TEST_F(GenerationNumberInterfaceTest, SaveLoadGenerationNumber) {
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_PrepareGenerationNumber());
const uint64_t generation_number = 42;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_SaveGenerationNumber(generation_number));
uint64_t generation_number_loaded;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_LoadGenerationNumber(&generation_number_loaded));
ASSERT_EQ(generation_number, generation_number_loaded);
}
class GenerationNumberRebootTest : public GenerationNumberInterfaceTest {};
TEST_F(GenerationNumberRebootTest, SaveBeforeReboot) {
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_PrepareGenerationNumber());
const uint64_t generation_number = 0xaa;
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_SaveGenerationNumber(generation_number));
}
TEST_F(GenerationNumberRebootTest, LoadAfterReboot) {
ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_PrepareGenerationNumber());
uint64_t generation_number_loaded;
ASSERT_EQ(OEMCrypto_SUCCESS,
WTPI_LoadGenerationNumber(&generation_number_loaded));
ASSERT_EQ((uint64_t)0xaa, generation_number_loaded);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#ifndef OPK_REE_SERIALIZER_H_
#define OPK_REE_SERIALIZER_H_
#include "log_macros.h"
#include "opk_serialization_base.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
ODK_Message OPK_Pack_PrepareGenerationNumber_Request(void);
void OPK_Unpack_PrepareGenerationNumber_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_LoadGenerationNumber_Request(const uint64_t* value);
void OPK_Unpack_LoadGenerationNumber_Response(ODK_Message* msg,
OEMCryptoResult* result,
uint64_t** value);
ODK_Message OPK_Pack_SaveGenerationNumber_Request(uint64_t value);
void OPK_Unpack_SaveGenerationNumber_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_K1_GetKeySize_Request(
WTPI_K1_SymmetricKey_Handle key_handle, const KeySize* size);
void OPK_Unpack_K1_GetKeySize_Response(ODK_Message* msg,
OEMCryptoResult* result, KeySize** size);
ODK_Message OPK_Pack_C1_AESCBCDecrypt_Request(
WTPI_K1_SymmetricKey_Handle key_handle, size_t key_length,
const uint8_t* in_buffer, size_t in_buffer_length, const uint8_t* iv,
const uint8_t* out_buffer);
void OPK_Unpack_C1_AESCBCDecrypt_Response(ODK_Message* msg,
OEMCryptoResult* result,
size_t* in_buffer_length,
uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_AESCBCEncrypt_Request(
WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* in_buffer,
size_t in_buffer_length, const uint8_t* iv, const uint8_t* out_buffer);
void OPK_Unpack_C1_AESCBCEncrypt_Response(ODK_Message* msg,
OEMCryptoResult* result,
size_t* in_buffer_length,
uint8_t** out_buffer);
void OPK_Unpack_C1_HMAC_SHA256_Verify_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_C1_CopyToOutputBuffer_Request(const uint8_t* input,
size_t input_length,
const OPK_OutputBuffer* out,
size_t output_offset);
void OPK_Unpack_C1_CopyToOutputBuffer_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_C1_RandomBytes_Request(const uint8_t* out,
size_t out_length);
void OPK_Unpack_C1_RandomBytes_Response(ODK_Message* msg,
OEMCryptoResult* result, uint8_t** out,
size_t* out_length);
ODK_Message OPK_Pack_K1_InitializeKeyManagement_Request(void);
void OPK_Unpack_K1_InitializeKeyManagement_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_K1_TerminateKeyManagement_Request(void);
void OPK_Unpack_K1_TerminateKeyManagement_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_K1_CreateKeyHandle_Request(
const uint8_t* input, size_t input_length, SymmetricKeyType key_type,
const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_CreateKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Request(
uint32_t context, SymmetricKeyType out_key_type,
const WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size);
void OPK_Unpack_K1_DeriveDeviceKeyIntoHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Request(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_key,
size_t enc_key_length, const uint8_t* iv, SymmetricKeyType key_type,
const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request(
WTPI_K1_SymmetricKey_Handle decrypt_key_handle, const uint8_t* enc_mac_keys,
size_t enc_mac_keys_length, const uint8_t* iv,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_client);
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_mac_key_server,
WTPI_K1_SymmetricKey_Handle** out_mac_key_client);
ODK_Message OPK_Pack_K1_DeriveKeyFromKeyHandle_Request(
WTPI_K1_SymmetricKey_Handle key_handle, uint8_t counter,
const uint8_t* context, size_t context_length,
SymmetricKeyType out_key_type, KeySize out_key_size,
const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_DeriveKeyFromKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_WrapKey_Request(uint32_t context,
WTPI_K1_SymmetricKey_Handle key_handle,
SymmetricKeyType key_type,
const uint8_t* wrapped_key,
size_t wrapped_key_length);
void OPK_Unpack_K1_WrapKey_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** wrapped_key,
size_t* wrapped_key_length);
ODK_Message OPK_Pack_K1_UnwrapIntoKeyHandle_Request(
uint32_t context, const uint8_t* wrapped_key, size_t wrapped_key_length,
SymmetricKeyType key_type,
const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_UnwrapIntoKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_FreeKeyHandle_Request(
WTPI_K1_SymmetricKey_Handle key_handle);
void OPK_Unpack_K1_FreeKeyHandle_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Request(
const uint8_t* input, size_t input_length, AsymmetricKeyType key_type,
const WTPI_AsymmetricKey_Handle* key_handle);
void OPK_Unpack_CreateAsymmetricKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_AsymmetricKey_Handle** key_handle);
ODK_Message OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Request(
const uint8_t* input, size_t input_length, AsymmetricKeyType key_type,
const WTPI_AsymmetricKey_Handle* key_handle,
const uint32_t* allowed_schemes);
void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Response(
ODK_Message* msg, OEMCryptoResult* result,
WTPI_AsymmetricKey_Handle** key_handle, uint32_t** allowed_schemes);
ODK_Message OPK_Pack_FreeAsymmetricKeyHandle_Request(
WTPI_AsymmetricKey_Handle key_handle);
void OPK_Unpack_FreeAsymmetricKeyHandle_Response(ODK_Message* msg,
OEMCryptoResult* result);
ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Request(
size_t enc_private_key_length, AsymmetricKeyType key_type,
const size_t* buffer_size);
void OPK_Unpack_GetWrappedAsymmetricKeySize_Response(ODK_Message* msg,
OEMCryptoResult* result,
size_t** buffer_size);
ODK_Message OPK_Pack_RSASign_Request(WTPI_AsymmetricKey_Handle key,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
const size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
void OPK_Unpack_RSASign_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** signature,
size_t** signature_length);
ODK_Message OPK_Pack_RSADecrypt_Request(WTPI_AsymmetricKey_Handle key,
const uint8_t* input,
size_t input_length, const uint8_t* out,
const size_t* out_length);
void OPK_Unpack_RSADecrypt_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** out, size_t** out_length);
ODK_Message OPK_Pack_ECCSign_Request(WTPI_AsymmetricKey_Handle key,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
const size_t* signature_length);
void OPK_Unpack_ECCSign_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** signature,
size_t** signature_length);
ODK_Message OPK_Pack_ECCDeriveSessionKey_Request(
WTPI_AsymmetricKey_Handle key, const uint8_t* key_source,
size_t key_source_length, const uint8_t* session_key,
const size_t* session_key_length);
void OPK_Unpack_ECCDeriveSessionKey_Response(ODK_Message* msg,
OEMCryptoResult* result,
uint8_t** session_key,
size_t** session_key_length);
ODK_Message OPK_Pack_GetSignatureSize_Request(WTPI_AsymmetricKey_Handle key,
const size_t* signature_length);
void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg,
OEMCryptoResult* result,
size_t** signature_length);
ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash);
void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result,
uint32_t** initial_hash);
ODK_Message OPK_Pack_Crc32Cont_Request(const uint8_t* in, size_t in_length,
uint32_t prev_crc,
const uint32_t* new_crc);
void OPK_Unpack_Crc32Cont_Response(ODK_Message* msg, OEMCryptoResult* result,
uint32_t** new_crc);
ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in,
size_t in_offset,
size_t in_length,
uint32_t prev_crc,
const uint32_t* new_crc);
void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg,
OEMCryptoResult* result,
uint32_t** new_crc);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPK_REE_SERIALIZER_H_ */

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
* source code may only be used and distributed under the Widevine License
* Agreement.
*/
#ifndef OPK_API_SUPPORT_H_
#define OPK_API_SUPPORT_H_
/*
* Support functions for the TEE API functions, related to message handling.
*/
#include <pthread.h>
#include "OEMCryptoCENC.h"
#include "bump_allocator.h"
#include "marshaller_base.h"
#include "shared_buffer_allocator.h"
#include "tos_shared_memory_interface.h"
#include "tos_transport_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
extern pthread_mutex_t api_lock;
extern OEMCryptoResult api_result;
void API_Initialize(void);
ODK_Message API_Transact(ODK_Message* request);
OEMCryptoResult API_CheckResult(OEMCryptoResult unpacked_result);
void API_Terminate(void);
#ifdef __cplusplus
}
#endif
#endif /* OPK_API_SUPPORT_H_ */

View File

@@ -0,0 +1,36 @@
#
# Builds the static library opk_ree.a, which includes Linux-based
# implementation of transport and shared memory.
#
# Dependencies:
# OPK serialization library for REE [ 'ree_api.gyp:opk_ree_api' ]
#
{
'includes' : [
'../settings.gypi',
],
'variables': {
'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/ipc-test/serialization_adapter',
},
'targets' : [
{
'target_name': 'opk_ree',
'type': 'static_library',
'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',
],
'link_settings': {
'libraries': [
'-lpthread',
'-lrt'
],
},
'dependencies': [
'<(ree_dir)/ree_api.gyp:opk_ree_api',
],
},
]
}

View File

@@ -0,0 +1,48 @@
#
# Builds the static library opk_ree_api.a from generated sources based on
# oemcrypto_wtpi_macros.h.
#
{
'includes': [
'../settings.gypi'
],
'target_defaults': {
'variables': {
# If |enable_code_generator| is true, the GEN_* files will be
# updated if they are out of date.
'enable_code_generator%': 'false',
},
},
'targets': [
{
'target_name': 'opk_ree_api',
'type': 'static_library',
'sources': [
'GEN_ree_serializer.c',
'GEN_oemcrypto_tee_test_api.c',
'ree_special_cases.c',
'<(common_dir)/GEN_common_serializer.c',
'<(common_dir)/common_special_cases.c',
'<(odk_dir)/src/odk_message.c',
'<(odk_dir)/src/odk_overflow.c',
'<(serialization_common_dir)/bump_allocator.c',
'<(serialization_common_dir)/log_macros.c',
'<(serialization_common_dir)/length_types.c',
'<(serialization_common_dir)/marshaller_base.c',
'<(serialization_common_dir)/opk_init.c',
'<(serialization_common_dir)/opk_serialization_base.c',
'<(serialization_common_dir)/shared_buffer_allocator.c',
'<(serialization_dir)/ree/api_support.c',
],
'conditions': [
['enable_code_generator=="true"', {
'dependencies': [
'<(wtpi_test_dir)/generator/make_source.gyp:make_api_src',
'<(wtpi_test_dir)/generator/make_source.gyp:make_common_serializer_src',
'<(wtpi_test_dir)/generator/make_source.gyp:make_ree_serializer_src',
],
}],
],
}
]
}

View File

@@ -0,0 +1,147 @@
/*
* 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 "ree_special_cases.h"
#include <time.h>
#include "GEN_common_serializer.h"
#include "bump_allocator.h"
#include "common_special_cases.h"
#include "log_macros.h"
#include "marshaller_base.h"
#include "odk_overflow.h"
#include "opk_serialization_base.h"
#include "shared_buffer_allocator.h"
#include "tos_transport_interface.h"
ODK_Message OPK_Pack_C1_HMAC_SHA256_Verify_Request(
WTPI_K1_SymmetricKey_Handle key, const uint8_t* in_buffer,
size_t in_buffer_length, const uint8_t* signature) {
uint32_t api_value = 10009; /* from _tee10009 */
ODK_Message msg = TOS_Transport_GetRequest();
OPK_Pack_uint32_t(&msg, &api_value);
uint64_t timestamp = time(0);
OPK_Pack_uint64_t(&msg, &timestamp);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &key);
OPK_PackMemory(&msg, in_buffer, OPK_ToLengthType(in_buffer_length));
OPK_PackMemory(&msg, signature, OPK_ToLengthType(32));
OPK_PackEOM(&msg);
return msg;
}
ODK_Message OPK_Pack_C1_SHA256_Request(const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer) {
uint32_t api_value = 10007; /* from _tee10007 */
ODK_Message msg = TOS_Transport_GetRequest();
OPK_Pack_uint32_t(&msg, &api_value);
uint64_t timestamp = time(0);
OPK_Pack_uint64_t(&msg, &timestamp);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_PackMemory(&msg, in_buffer, OPK_ToLengthType(in_buffer_length));
OPK_PackAlloc(&msg, out_buffer);
OPK_PackEOM(&msg);
return msg;
}
void OPK_Unpack_C1_SHA256_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10007)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
OPK_Unpack_uint32_t(msg, result);
if (!Is_Valid_OEMCryptoResult(*result)) {
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE);
}
if (SuccessResult(*result)) {
uint8_t* p;
size_t out_length = 32;
OPK_UnpackInPlace(msg, &p, OPK_ToLengthType(out_length));
if (p && *out_buffer) {
memcpy(*out_buffer, p, out_length);
}
}
OPK_UnpackEOM(msg);
}
ODK_Message OPK_Pack_C1_HMAC_SHA1_Request(WTPI_K1_SymmetricKey_Handle key,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer) {
uint32_t api_value = 10006; /* from _tee10006 */
ODK_Message msg = TOS_Transport_GetRequest();
OPK_Pack_uint32_t(&msg, &api_value);
uint64_t timestamp = time(0);
OPK_Pack_uint64_t(&msg, &timestamp);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &key);
OPK_PackMemory(&msg, in_buffer, OPK_ToLengthType(in_buffer_length));
OPK_PackAlloc(&msg, out_buffer);
OPK_PackEOM(&msg);
return msg;
}
void OPK_Unpack_C1_HMAC_SHA1_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10006)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
OPK_Unpack_uint32_t(msg, result);
if (!Is_Valid_OEMCryptoResult(*result)) {
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE);
}
if (SuccessResult(*result)) {
uint8_t* p;
size_t out_length = 20;
OPK_UnpackInPlace(msg, &p, OPK_ToLengthType(out_length));
if (p && *out_buffer) {
memcpy(*out_buffer, p, out_length);
}
}
OPK_UnpackEOM(msg);
}
ODK_Message OPK_Pack_C1_HMAC_SHA256_Request(WTPI_K1_SymmetricKey_Handle key,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer) {
uint32_t api_value = 10008; /* from _tee10008 */
ODK_Message msg = TOS_Transport_GetRequest();
OPK_Pack_uint32_t(&msg, &api_value);
uint64_t timestamp = time(0);
OPK_Pack_uint64_t(&msg, &timestamp);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_Pack_WTPI_K1_SymmetricKey_Handle(&msg, &key);
OPK_PackMemory(&msg, in_buffer, OPK_ToLengthType(in_buffer_length));
OPK_PackAlloc(&msg, out_buffer);
OPK_PackEOM(&msg);
return msg;
}
void OPK_Unpack_C1_HMAC_SHA256_Response(ODK_Message* msg,
OEMCryptoResult* result,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10008)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
OPK_Unpack_uint32_t(msg, result);
if (!Is_Valid_OEMCryptoResult(*result)) {
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE);
}
if (SuccessResult(*result)) {
uint8_t* p;
size_t out_length = 32;
OPK_UnpackInPlace(msg, &p, OPK_ToLengthType(out_length));
if (p && *out_buffer) {
memcpy(*out_buffer, p, out_length);
}
}
OPK_UnpackEOM(msg);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2020 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_REE_SPECIAL_CASES_H_
#define WTPI_TEST_REE_SPECIAL_CASES_H_
#include "odk_message.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
void OPK_Pack_SymmetricKeyType(ODK_Message* msg,
const SymmetricKeyType* key_type);
void OPK_Unpack_SymmetricKeyType(ODK_Message* msg, SymmetricKeyType* key_type);
void OPK_Pack_AsymmetricKeyType(ODK_Message* msg,
const AsymmetricKeyType* key_type);
void OPK_Unpack_AsymmetricKeyType(ODK_Message* msg,
AsymmetricKeyType* key_type);
void OPK_Pack_RSA_Padding_Scheme(ODK_Message* msg,
const RSA_Padding_Scheme* padding_scheme);
void OPK_Unpack_RSA_Padding_Scheme(ODK_Message* msg,
RSA_Padding_Scheme* padding_scheme);
void OPK_Pack_KeySize(ODK_Message* msg, const KeySize* key_size);
void OPK_Unpack_KeySize(ODK_Message* msg, KeySize* key_size);
ODK_Message OPK_Pack_C1_HMAC_SHA256_Verify_Request(
WTPI_K1_SymmetricKey_Handle key, const uint8_t* in_buffer,
size_t in_buffer_length, const uint8_t* signature);
ODK_Message OPK_Pack_C1_SHA256_Request(const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer);
void OPK_Unpack_C1_SHA256_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** out_buffer);
void OPK_Unpack_C1_HMAC_SHA1_Response(ODK_Message* msg, OEMCryptoResult* result,
uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_HMAC_SHA1_Request(WTPI_K1_SymmetricKey_Handle key,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer);
ODK_Message OPK_Pack_C1_HMAC_SHA256_Request(WTPI_K1_SymmetricKey_Handle key,
const uint8_t* in_buffer,
size_t in_buffer_length,
const uint8_t* out_buffer);
void OPK_Unpack_C1_HMAC_SHA256_Response(ODK_Message* msg,
OEMCryptoResult* result,
uint8_t** out_buffer);
#endif

View File

@@ -0,0 +1,43 @@
{
'variables': {
'oemcrypto_dir' : '<(DEPTH)/oemcrypto',
'odk_dir' : '<(oemcrypto_dir)/odk',
'oemcrypto_ta_dir' : '<(oemcrypto_dir)/opk/oemcrypto_ta',
'serialization_dir' : '<(oemcrypto_dir)/opk/serialization',
'serialization_common_dir' : '<(serialization_dir)/common',
'serialization_generator_dir' : '<(serialization_dir)/generator',
'os_interfaces_dir' : '<(serialization_dir)/os_interfaces',
'wtpi_dir' : '<(oemcrypto_ta_dir)/wtpi',
'wtpi_test_dir' : '<(oemcrypto_ta_dir)/wtpi_test',
'common_dir' : '<(wtpi_test_dir)/common',
'ree_dir' : '<(wtpi_test_dir)/ree',
'tee_dir' : '<(wtpi_test_dir)/tee',
'third_party_dir' : '<(DEPTH)/third_party',
'json_dir' : '<(third_party_dir)/nlohmann-json',
'util_dir' : '<(DEPTH)/util',
},
'target_defaults' : {
'cflags' : [
'-g',
'-Werror=all',
],
'include_dirs' : [
'.',
'<(common_dir)',
'<(json_dir)/single_include',
'<(odk_dir)/include',
'<(odk_dir)/src',
'<(oemcrypto_dir)/include',
'<(oemcrypto_ta_dir)',
'<(oemcrypto_ta_dir)/wtpi',
'<(os_interfaces_dir)',
'<(serialization_common_dir)/include',
'<(serialization_generator_dir)',
],
'defines' : [
'ENABLE_LOGGING=1',
'MIN_LOG_LEVEL=LOG_LEVEL_DEBUG',
'ENABLE_ANSI_COLORS=1',
],
}
}

View File

@@ -0,0 +1,767 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#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 "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 "wtpi_generation_number_interface.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_Substring(OEMCrypto_Substring* obj) {
OPK_Init_size_t((size_t*)&obj->offset);
OPK_Init_size_t((size_t*)&obj->length);
}
void OPK_Init_OEMCrypto_KeyObject(OEMCrypto_KeyObject* obj) {
OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_id);
OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_data_iv);
OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_data);
OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control_iv);
OPK_Init_OEMCrypto_Substring((OEMCrypto_Substring*)&obj->key_control);
}
/* See opk_dispatcher.h for definition of OPK_DispatchMessage() */
ODK_MessageStatus OPK_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, &timestamp);
OPK_SetWallClockTime(timestamp);
OPK_BumpAllocator_Reset();
OPK_SharedBuffer_Reset();
ODK_Message_Reset(request);
switch (api_value) {
case 10000: /* WTPI_PrepareGenerationNumber */
{
OPK_Unpack_PrepareGenerationNumber_Request(request);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("PrepareGenerationNumber");
result = WTPI_PrepareGenerationNumber();
*response = OPK_Pack_PrepareGenerationNumber_Response(result);
break;
}
case 10001: /* WTPI_LoadGenerationNumber */
{
uint64_t* value;
OPK_InitPointer((uint8_t**)&value);
OPK_Unpack_LoadGenerationNumber_Request(request, &value);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("LoadGenerationNumber");
result = WTPI_LoadGenerationNumber(value);
*response = OPK_Pack_LoadGenerationNumber_Response(result, value);
break;
}
case 10002: /* WTPI_SaveGenerationNumber */
{
uint64_t value;
OPK_Init_uint64_t((uint64_t*)&value);
OPK_Unpack_SaveGenerationNumber_Request(request, &value);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("SaveGenerationNumber");
result = WTPI_SaveGenerationNumber(value);
*response = OPK_Pack_SaveGenerationNumber_Response(result);
break;
}
case 10003: /* WTPI_K1_GetKeySize */
{
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
KeySize* size;
OPK_InitPointer((uint8_t**)&size);
OPK_Unpack_K1_GetKeySize_Request(request, &key_handle, &size);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_GetKeySize");
result = WTPI_K1_GetKeySize(key_handle, size);
*response = OPK_Pack_K1_GetKeySize_Response(result, size);
break;
}
case 10004: /* WTPI_C1_AESCBCDecrypt */
{
size_t in_buffer_length;
OPK_Init_size_t((size_t*)&in_buffer_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
size_t key_length;
OPK_Init_size_t((size_t*)&key_length);
uint8_t* in_buffer;
OPK_InitPointer((uint8_t**)&in_buffer);
uint8_t iv[16];
OPK_InitMemory(&iv[0], 16);
uint8_t* out_buffer;
OPK_InitPointer((uint8_t**)&out_buffer);
OPK_Unpack_C1_AESCBCDecrypt_Request(request, &key_handle, &key_length,
&in_buffer, &in_buffer_length, &iv[0],
&out_buffer);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_AESCBCDecrypt");
result = WTPI_C1_AESCBCDecrypt(key_handle, key_length, in_buffer,
in_buffer_length, iv, out_buffer);
*response = OPK_Pack_C1_AESCBCDecrypt_Response(result, in_buffer_length,
out_buffer);
break;
}
case 10005: /* WTPI_C1_AESCBCEncrypt */
{
size_t in_buffer_length;
OPK_Init_size_t((size_t*)&in_buffer_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
uint8_t* in_buffer;
OPK_InitPointer((uint8_t**)&in_buffer);
uint8_t iv[16];
OPK_InitMemory(&iv[0], 16);
uint8_t* out_buffer;
OPK_InitPointer((uint8_t**)&out_buffer);
OPK_Unpack_C1_AESCBCEncrypt_Request(request, &key_handle, &in_buffer,
&in_buffer_length, &iv[0],
&out_buffer);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_AESCBCEncrypt");
result = WTPI_C1_AESCBCEncrypt(key_handle, in_buffer, in_buffer_length,
iv, out_buffer);
*response = OPK_Pack_C1_AESCBCEncrypt_Response(result, in_buffer_length,
out_buffer);
break;
}
case 10006: /* WTPI_C1_HMAC_SHA1 */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
uint8_t* out_buffer;
OPK_InitPointer((uint8_t**)&out_buffer);
OPK_Unpack_C1_HMAC_SHA1_Request(request, &key_handle, &input,
&input_length, &out_buffer);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_HMAC_SHA1");
result = WTPI_C1_HMAC_SHA1(key_handle, input, input_length, out_buffer);
*response = OPK_Pack_C1_HMAC_SHA1_Response(result, out_buffer);
break;
}
case 10007: /* WTPI_C1_SHA256 */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
uint8_t* out_buffer;
OPK_InitPointer((uint8_t**)&out_buffer);
OPK_Unpack_C1_SHA256_Request(request, &input, &input_length, &out_buffer);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_SHA256");
result = WTPI_C1_SHA256(input, input_length, out_buffer);
*response = OPK_Pack_C1_SHA256_Response(result, out_buffer);
break;
}
case 10008: /* WTPI_C1_HMAC_SHA256 */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
uint8_t* out_buffer;
OPK_InitPointer((uint8_t**)&out_buffer);
OPK_Unpack_C1_HMAC_SHA256_Request(request, &key_handle, &input,
&input_length, &out_buffer);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_HMAC_SHA256");
result = WTPI_C1_HMAC_SHA256(key_handle, input, input_length, out_buffer);
*response = OPK_Pack_C1_HMAC_SHA256_Response(result, out_buffer);
break;
}
case 10009: /* WTPI_C1_HMAC_SHA256_Verify */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
uint8_t* signature = (uint8_t*)OPK_VarAlloc(sizeof(uint8_t));
OPK_Init_uint8_t((uint8_t*)signature);
OPK_Unpack_C1_HMAC_SHA256_Verify_Request(request, &key_handle, &input,
&input_length, &signature);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_HMAC_SHA256_Verify");
result = WTPI_C1_HMAC_SHA256_Verify(key_handle, input, input_length,
signature);
*response = OPK_Pack_C1_HMAC_SHA256_Verify_Response(result);
break;
}
case 10010: /* WTPI_C1_CopyToOutputBuffer */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
OPK_OutputBuffer* out =
(OPK_OutputBuffer*)OPK_VarAlloc(sizeof(OPK_OutputBuffer));
OPK_Init_OPK_OutputBuffer((OPK_OutputBuffer*)out);
size_t output_offset;
OPK_Init_size_t((size_t*)&output_offset);
OPK_Unpack_C1_CopyToOutputBuffer_Request(request, &input, &input_length,
&out, &output_offset);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_CopyToOutputBuffer");
result =
WTPI_C1_CopyToOutputBuffer(input, input_length, out, output_offset);
*response = OPK_Pack_C1_CopyToOutputBuffer_Response(result);
break;
}
case 10011: /* WTPI_C1_RandomBytes */
{
size_t out_length;
OPK_Init_size_t((size_t*)&out_length);
uint8_t* out;
OPK_InitPointer((uint8_t**)&out);
OPK_Unpack_C1_RandomBytes_Request(request, &out, &out_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("C1_RandomBytes");
result = WTPI_C1_RandomBytes(out, out_length);
*response = OPK_Pack_C1_RandomBytes_Response(result, out, out_length);
break;
}
case 10012: /* WTPI_K1_InitializeKeyManagement */
{
OPK_Unpack_K1_InitializeKeyManagement_Request(request);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_InitializeKeyManagement");
result = WTPI_K1_InitializeKeyManagement();
*response = OPK_Pack_K1_InitializeKeyManagement_Response(result);
break;
}
case 10013: /* WTPI_K1_TerminateKeyManagement */
{
OPK_Unpack_K1_TerminateKeyManagement_Request(request);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_TerminateKeyManagement");
result = WTPI_K1_TerminateKeyManagement();
*response = OPK_Pack_K1_TerminateKeyManagement_Response(result);
break;
}
case 10014: /* WTPI_K1_CreateKeyHandle */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
SymmetricKeyType key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&key_type);
WTPI_K1_SymmetricKey_Handle* out_key_handle;
OPK_InitPointer((uint8_t**)&out_key_handle);
OPK_Unpack_K1_CreateKeyHandle_Request(request, &input, &input_length,
&key_type, &out_key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_CreateKeyHandle");
result = WTPI_K1_CreateKeyHandle(input, input_length, key_type,
out_key_handle);
*response = OPK_Pack_K1_CreateKeyHandle_Response(result, out_key_handle);
break;
}
case 10015: /* WTPI_K1_DeriveDeviceKeyIntoHandle */
{
uint32_t context;
OPK_Init_uint32_t((uint32_t*)&context);
SymmetricKeyType out_key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&out_key_type);
WTPI_K1_SymmetricKey_Handle* out_key_handle;
OPK_InitPointer((uint8_t**)&out_key_handle);
KeySize out_key_size;
OPK_Init_KeySize((KeySize*)&out_key_size);
OPK_Unpack_K1_DeriveDeviceKeyIntoHandle_Request(
request, &context, &out_key_type, &out_key_handle, &out_key_size);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_DeriveDeviceKeyIntoHandle");
result = WTPI_K1_DeriveDeviceKeyIntoHandle(context, out_key_type,
out_key_handle, out_key_size);
*response = OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Response(
result, out_key_handle);
break;
}
case 10016: /* WTPI_K1_AESDecryptAndCreateKeyHandle */
{
size_t enc_key_length;
OPK_Init_size_t((size_t*)&enc_key_length);
WTPI_K1_SymmetricKey_Handle decrypt_key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&decrypt_key_handle);
uint8_t* enc_key;
OPK_InitPointer((uint8_t**)&enc_key);
uint8_t iv[16];
OPK_InitMemory(&iv[0], 16);
SymmetricKeyType key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&key_type);
WTPI_K1_SymmetricKey_Handle* out_key_handle;
OPK_InitPointer((uint8_t**)&out_key_handle);
OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request(
request, &decrypt_key_handle, &enc_key, &enc_key_length, &iv[0],
&key_type, &out_key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_AESDecryptAndCreateKeyHandle");
result = WTPI_K1_AESDecryptAndCreateKeyHandle(decrypt_key_handle, enc_key,
enc_key_length, iv,
key_type, out_key_handle);
*response = OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Response(
result, out_key_handle);
break;
}
case 10017: /* WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys */
{
size_t enc_mac_keys_length;
OPK_Init_size_t((size_t*)&enc_mac_keys_length);
WTPI_K1_SymmetricKey_Handle decrypt_key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&decrypt_key_handle);
uint8_t* enc_mac_keys;
OPK_InitPointer((uint8_t**)&enc_mac_keys);
uint8_t iv[16];
OPK_InitMemory(&iv[0], 16);
WTPI_K1_SymmetricKey_Handle* out_mac_key_server;
OPK_InitPointer((uint8_t**)&out_mac_key_server);
WTPI_K1_SymmetricKey_Handle* out_mac_key_client;
OPK_InitPointer((uint8_t**)&out_mac_key_client);
OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request(
request, &decrypt_key_handle, &enc_mac_keys, &enc_mac_keys_length,
&iv[0], &out_mac_key_server, &out_mac_key_client);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_AESDecryptAndCreateKeyHandleForMacKeys");
result = WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys(
decrypt_key_handle, enc_mac_keys, enc_mac_keys_length, iv,
out_mac_key_server, out_mac_key_client);
*response = OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Response(
result, out_mac_key_server, out_mac_key_client);
break;
}
case 10018: /* WTPI_K1_DeriveKeyFromKeyHandle */
{
size_t context_length;
OPK_Init_size_t((size_t*)&context_length);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
uint8_t counter;
OPK_Init_uint8_t((uint8_t*)&counter);
uint8_t* context;
OPK_InitPointer((uint8_t**)&context);
SymmetricKeyType out_key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&out_key_type);
KeySize out_key_size;
OPK_Init_KeySize((KeySize*)&out_key_size);
WTPI_K1_SymmetricKey_Handle* out_key_handle;
OPK_InitPointer((uint8_t**)&out_key_handle);
OPK_Unpack_K1_DeriveKeyFromKeyHandle_Request(
request, &key_handle, &counter, &context, &context_length,
&out_key_type, &out_key_size, &out_key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_DeriveKeyFromKeyHandle");
result = WTPI_K1_DeriveKeyFromKeyHandle(key_handle, counter, context,
context_length, out_key_type,
out_key_size, out_key_handle);
*response =
OPK_Pack_K1_DeriveKeyFromKeyHandle_Response(result, out_key_handle);
break;
}
case 10019: /* WTPI_K1_WrapKey */
{
size_t wrapped_key_length;
OPK_Init_size_t((size_t*)&wrapped_key_length);
uint32_t context;
OPK_Init_uint32_t((uint32_t*)&context);
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
SymmetricKeyType key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&key_type);
uint8_t* wrapped_key;
OPK_InitPointer((uint8_t**)&wrapped_key);
OPK_Unpack_K1_WrapKey_Request(request, &context, &key_handle, &key_type,
&wrapped_key, &wrapped_key_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_WrapKey");
result = WTPI_K1_WrapKey(context, key_handle, key_type, wrapped_key,
wrapped_key_length);
*response =
OPK_Pack_K1_WrapKey_Response(result, wrapped_key, wrapped_key_length);
break;
}
case 10020: /* WTPI_K1_UnwrapIntoKeyHandle */
{
size_t wrapped_key_length;
OPK_Init_size_t((size_t*)&wrapped_key_length);
uint32_t context;
OPK_Init_uint32_t((uint32_t*)&context);
uint8_t* wrapped_key;
OPK_InitPointer((uint8_t**)&wrapped_key);
SymmetricKeyType key_type;
OPK_Init_SymmetricKeyType((SymmetricKeyType*)&key_type);
WTPI_K1_SymmetricKey_Handle* out_key_handle;
OPK_InitPointer((uint8_t**)&out_key_handle);
OPK_Unpack_K1_UnwrapIntoKeyHandle_Request(request, &context, &wrapped_key,
&wrapped_key_length, &key_type,
&out_key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_UnwrapIntoKeyHandle");
result = WTPI_K1_UnwrapIntoKeyHandle(
context, wrapped_key, wrapped_key_length, key_type, out_key_handle);
*response =
OPK_Pack_K1_UnwrapIntoKeyHandle_Response(result, out_key_handle);
break;
}
case 10021: /* WTPI_K1_FreeKeyHandle */
{
WTPI_K1_SymmetricKey_Handle key_handle;
OPK_Init_WTPI_K1_SymmetricKey_Handle(
(WTPI_K1_SymmetricKey_Handle*)&key_handle);
OPK_Unpack_K1_FreeKeyHandle_Request(request, &key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("K1_FreeKeyHandle");
result = WTPI_K1_FreeKeyHandle(key_handle);
*response = OPK_Pack_K1_FreeKeyHandle_Response(result);
break;
}
case 10022: /* WTPI_CreateAsymmetricKeyHandle */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
AsymmetricKeyType key_type;
OPK_Init_AsymmetricKeyType((AsymmetricKeyType*)&key_type);
WTPI_AsymmetricKey_Handle* key_handle;
OPK_InitPointer((uint8_t**)&key_handle);
OPK_Unpack_CreateAsymmetricKeyHandle_Request(
request, &input, &input_length, &key_type, &key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("CreateAsymmetricKeyHandle");
result = WTPI_CreateAsymmetricKeyHandle(input, input_length, key_type,
key_handle);
*response =
OPK_Pack_CreateAsymmetricKeyHandle_Response(result, key_handle);
break;
}
case 10023: /* WTPI_UnwrapIntoAsymmetricKeyHandle */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
AsymmetricKeyType key_type;
OPK_Init_AsymmetricKeyType((AsymmetricKeyType*)&key_type);
WTPI_AsymmetricKey_Handle* key_handle;
OPK_InitPointer((uint8_t**)&key_handle);
uint32_t* allowed_schemes;
OPK_InitPointer((uint8_t**)&allowed_schemes);
OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Request(
request, &input, &input_length, &key_type, &key_handle,
&allowed_schemes);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("UnwrapIntoAsymmetricKeyHandle");
result = WTPI_UnwrapIntoAsymmetricKeyHandle(input, input_length, key_type,
key_handle, allowed_schemes);
*response = OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Response(
result, key_handle, allowed_schemes);
break;
}
case 10024: /* WTPI_FreeAsymmetricKeyHandle */
{
WTPI_AsymmetricKey_Handle key_handle;
OPK_Init_WTPI_AsymmetricKey_Handle(
(WTPI_AsymmetricKey_Handle*)&key_handle);
OPK_Unpack_FreeAsymmetricKeyHandle_Request(request, &key_handle);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("FreeAsymmetricKeyHandle");
result = WTPI_FreeAsymmetricKeyHandle(key_handle);
*response = OPK_Pack_FreeAsymmetricKeyHandle_Response(result);
break;
}
case 10025: /* WTPI_GetWrappedAsymmetricKeySize */
{
size_t enc_private_key_length;
OPK_Init_size_t((size_t*)&enc_private_key_length);
AsymmetricKeyType key_type;
OPK_Init_AsymmetricKeyType((AsymmetricKeyType*)&key_type);
size_t* buffer_size;
OPK_InitPointer((uint8_t**)&buffer_size);
OPK_Unpack_GetWrappedAsymmetricKeySize_Request(
request, &enc_private_key_length, &key_type, &buffer_size);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("GetWrappedAsymmetricKeySize");
result = WTPI_GetWrappedAsymmetricKeySize(enc_private_key_length,
key_type, buffer_size);
*response =
OPK_Pack_GetWrappedAsymmetricKeySize_Response(result, buffer_size);
break;
}
case 10026: /* WTPI_RSASign */
{
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
OPK_Init_size_t(signature_length);
WTPI_AsymmetricKey_Handle key;
OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key);
uint8_t* message;
OPK_InitPointer((uint8_t**)&message);
uint8_t* signature;
OPK_InitPointer((uint8_t**)&signature);
RSA_Padding_Scheme padding_scheme;
OPK_Init_RSA_Padding_Scheme((RSA_Padding_Scheme*)&padding_scheme);
OPK_Unpack_RSASign_Request(request, &key, &message, &message_length,
&signature, &signature_length,
&padding_scheme);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("RSASign");
result = WTPI_RSASign(key, message, message_length, signature,
signature_length, padding_scheme);
*response =
OPK_Pack_RSASign_Response(result, signature, signature_length);
break;
}
case 10027: /* WTPI_RSADecrypt */
{
size_t input_length;
OPK_Init_size_t((size_t*)&input_length);
size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
OPK_Init_size_t(out_length);
WTPI_AsymmetricKey_Handle key;
OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key);
uint8_t* input;
OPK_InitPointer((uint8_t**)&input);
uint8_t* out;
OPK_InitPointer((uint8_t**)&out);
OPK_Unpack_RSADecrypt_Request(request, &key, &input, &input_length, &out,
&out_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("RSADecrypt");
result = WTPI_RSADecrypt(key, input, input_length, out, out_length);
*response = OPK_Pack_RSADecrypt_Response(result, out, out_length);
break;
}
case 10028: /* WTPI_ECCSign */
{
size_t message_length;
OPK_Init_size_t((size_t*)&message_length);
size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
OPK_Init_size_t(signature_length);
WTPI_AsymmetricKey_Handle key;
OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key);
uint8_t* message;
OPK_InitPointer((uint8_t**)&message);
uint8_t* signature;
OPK_InitPointer((uint8_t**)&signature);
OPK_Unpack_ECCSign_Request(request, &key, &message, &message_length,
&signature, &signature_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("ECCSign");
result = WTPI_ECCSign(key, message, message_length, signature,
signature_length);
*response =
OPK_Pack_ECCSign_Response(result, signature, signature_length);
break;
}
case 10029: /* WTPI_ECCDeriveSessionKey */
{
size_t key_source_length;
OPK_Init_size_t((size_t*)&key_source_length);
size_t* session_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t));
OPK_Init_size_t(session_key_length);
WTPI_AsymmetricKey_Handle key;
OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key);
uint8_t* key_source;
OPK_InitPointer((uint8_t**)&key_source);
uint8_t* session_key;
OPK_InitPointer((uint8_t**)&session_key);
OPK_Unpack_ECCDeriveSessionKey_Request(request, &key, &key_source,
&key_source_length, &session_key,
&session_key_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("ECCDeriveSessionKey");
result = WTPI_ECCDeriveSessionKey(key, key_source, key_source_length,
session_key, session_key_length);
*response = OPK_Pack_ECCDeriveSessionKey_Response(result, session_key,
session_key_length);
break;
}
case 10030: /* WTPI_GetSignatureSize */
{
WTPI_AsymmetricKey_Handle key;
OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key);
size_t* signature_length;
OPK_InitPointer((uint8_t**)&signature_length);
OPK_Unpack_GetSignatureSize_Request(request, &key, &signature_length);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("GetSignatureSize");
result = WTPI_GetSignatureSize(key, signature_length);
*response = OPK_Pack_GetSignatureSize_Response(result, signature_length);
break;
}
case 10031: /* WTPI_Crc32Init */
{
uint32_t* initial_hash;
OPK_InitPointer((uint8_t**)&initial_hash);
OPK_Unpack_Crc32Init_Request(request, &initial_hash);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("Crc32Init");
result = WTPI_Crc32Init(initial_hash);
*response = OPK_Pack_Crc32Init_Response(result, initial_hash);
break;
}
case 10032: /* WTPI_Crc32Cont */
{
size_t in_length;
OPK_Init_size_t((size_t*)&in_length);
uint8_t* in;
OPK_InitPointer((uint8_t**)&in);
uint32_t prev_crc;
OPK_Init_uint32_t((uint32_t*)&prev_crc);
uint32_t* new_crc;
OPK_InitPointer((uint8_t**)&new_crc);
OPK_Unpack_Crc32Cont_Request(request, &in, &in_length, &prev_crc,
&new_crc);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("Crc32Cont");
result = WTPI_Crc32Cont(in, in_length, prev_crc, new_crc);
*response = OPK_Pack_Crc32Cont_Response(result, new_crc);
break;
}
case 10033: /* WTPI_Crc32Cont_OutputBuffer */
{
size_t in_length;
OPK_Init_size_t((size_t*)&in_length);
OPK_OutputBuffer* in;
OPK_InitPointer((uint8_t**)&in);
size_t in_offset;
OPK_Init_size_t((size_t*)&in_offset);
uint32_t prev_crc;
OPK_Init_uint32_t((uint32_t*)&prev_crc);
uint32_t* new_crc;
OPK_InitPointer((uint8_t**)&new_crc);
OPK_Unpack_Crc32Cont_OutputBuffer_Request(
request, &in, &in_offset, &in_length, &prev_crc, &new_crc);
if (!ODK_Message_IsValid(request)) goto handle_invalid_request;
OEMCryptoResult result;
OPK_Init_uint32_t((uint32_t*)&result);
LOGD("Crc32Cont_OutputBuffer");
result = WTPI_Crc32Cont_OutputBuffer(in, in_offset, in_length, prev_crc,
new_crc);
*response = OPK_Pack_Crc32Cont_OutputBuffer_Response(result, new_crc);
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;
}

View File

@@ -0,0 +1,965 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#include "GEN_tee_serializer.h"
#include <string.h>
#include <time.h>
#include "GEN_common_serializer.h"
#include "bump_allocator.h"
#include "common_special_cases.h"
#include "log_macros.h"
#include "marshaller_base.h"
#include "odk_overflow.h"
#include "opk_serialization_base.h"
#include "shared_buffer_allocator.h"
#include "tee_special_cases.h"
#include "tos_transport_interface.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
void OPK_Unpack_PrepareGenerationNumber_Request(ODK_Message* msg) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10000)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_PrepareGenerationNumber_Response(OEMCryptoResult result) {
uint32_t api_value = 10000; /* from _tee10000 */
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;
}
void OPK_Unpack_LoadGenerationNumber_Request(ODK_Message* msg,
uint64_t** value) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10001)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
*value = (uint64_t*)OPK_UnpackAlloc(msg, sizeof(uint64_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_LoadGenerationNumber_Response(OEMCryptoResult result,
const uint64_t* value) {
uint32_t api_value = 10001; /* from _tee10001 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_uint64_t(&msg, value);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_SaveGenerationNumber_Request(ODK_Message* msg,
uint64_t* value) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10002)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_uint64_t(msg, value);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_SaveGenerationNumber_Response(OEMCryptoResult result) {
uint32_t api_value = 10002; /* from _tee10002 */
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;
}
void OPK_Unpack_K1_GetKeySize_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key_handle,
KeySize** size) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10003)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
*size = (KeySize*)OPK_UnpackAlloc(msg, sizeof(KeySize));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_GetKeySize_Response(OEMCryptoResult result,
const KeySize* size) {
uint32_t api_value = 10003; /* from _tee10003 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_KeySize(&msg, size);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_C1_AESCBCDecrypt_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle,
size_t* key_length, uint8_t** in_buffer, size_t* in_buffer_length,
uint8_t* iv, uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10004)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_buffer_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
OPK_Unpack_size_t(msg, key_length);
OPK_UnpackInPlace(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length));
OPK_UnpackArray(msg, &iv[0], 16);
*out_buffer = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtr(in_buffer_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_C1_AESCBCDecrypt_Response(OEMCryptoResult result,
size_t in_buffer_length,
const uint8_t* out_buffer) {
uint32_t api_value = 10004; /* from _tee10004 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, out_buffer, OPK_ToLengthType(in_buffer_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_C1_AESCBCEncrypt_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle,
uint8_t** in_buffer, size_t* in_buffer_length, uint8_t* iv,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10005)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_buffer_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
OPK_UnpackInPlace(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length));
OPK_UnpackArray(msg, &iv[0], 16);
*out_buffer = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtr(in_buffer_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_C1_AESCBCEncrypt_Response(OEMCryptoResult result,
size_t in_buffer_length,
const uint8_t* out_buffer) {
uint32_t api_value = 10005; /* from _tee10005 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_size_t(&msg, &in_buffer_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, out_buffer, OPK_ToLengthType(in_buffer_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
ODK_Message OPK_Pack_C1_HMAC_SHA256_Verify_Response(OEMCryptoResult result) {
uint32_t api_value = 10009; /* from _tee10009 */
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;
}
void OPK_Unpack_C1_CopyToOutputBuffer_Request(ODK_Message* msg, uint8_t** input,
size_t* input_length,
OPK_OutputBuffer** out,
size_t* output_offset) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10010)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, input_length);
OPK_UnpackInPlace(msg, input, OPK_FromSizeTPtr(input_length));
OPK_UnpackNullable_OPK_OutputBuffer(msg, out);
OPK_Unpack_size_t(msg, output_offset);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_C1_CopyToOutputBuffer_Response(OEMCryptoResult result) {
uint32_t api_value = 10010; /* from _tee10010 */
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;
}
void OPK_Unpack_C1_RandomBytes_Request(ODK_Message* msg, uint8_t** out,
size_t* out_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10011)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, out_length);
*out = (uint8_t*)OPK_UnpackAllocBuffer(msg, OPK_FromSizeTPtr(out_length),
sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_C1_RandomBytes_Response(OEMCryptoResult result,
const uint8_t* out,
size_t out_length) {
uint32_t api_value = 10011; /* from _tee10011 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_size_t(&msg, &out_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, out, OPK_ToLengthType(out_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_InitializeKeyManagement_Request(ODK_Message* msg) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10012)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_InitializeKeyManagement_Response(
OEMCryptoResult result) {
uint32_t api_value = 10012; /* from _tee10012 */
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;
}
void OPK_Unpack_K1_TerminateKeyManagement_Request(ODK_Message* msg) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10013)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_TerminateKeyManagement_Response(
OEMCryptoResult result) {
uint32_t api_value = 10013; /* from _tee10013 */
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;
}
void OPK_Unpack_K1_CreateKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10014)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, input_length);
OPK_UnpackInPlace(msg, input, OPK_FromSizeTPtr(input_length));
OPK_Unpack_SymmetricKeyType(msg, key_type);
*out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_CreateKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle) {
uint32_t api_value = 10014; /* from _tee10014 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_DeriveDeviceKeyIntoHandle_Request(
ODK_Message* msg, uint32_t* context, SymmetricKeyType* out_key_type,
WTPI_K1_SymmetricKey_Handle** out_key_handle, KeySize* out_key_size) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10015)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_uint32_t(msg, context);
OPK_Unpack_SymmetricKeyType(msg, out_key_type);
*out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_Unpack_KeySize(msg, out_key_size);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle) {
uint32_t api_value = 10015; /* from _tee10015 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle,
uint8_t** enc_key, size_t* enc_key_length, uint8_t* iv,
SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10016)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, enc_key_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, decrypt_key_handle);
OPK_UnpackInPlace(msg, enc_key, OPK_FromSizeTPtr(enc_key_length));
OPK_UnpackArray(msg, &iv[0], 16);
OPK_Unpack_SymmetricKeyType(msg, key_type);
*out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle) {
uint32_t api_value = 10016; /* from _tee10016 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle,
uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t* iv,
WTPI_K1_SymmetricKey_Handle** out_mac_key_server,
WTPI_K1_SymmetricKey_Handle** out_mac_key_client) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10017)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, enc_mac_keys_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, decrypt_key_handle);
OPK_UnpackInPlace(msg, enc_mac_keys, OPK_FromSizeTPtr(enc_mac_keys_length));
OPK_UnpackArray(msg, &iv[0], 16);
*out_mac_key_server = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
*out_mac_key_client = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Response(
OEMCryptoResult result,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_client) {
uint32_t api_value = 10017; /* from _tee10017 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_mac_key_server);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_mac_key_client);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_DeriveKeyFromKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, uint8_t* counter,
uint8_t** context, size_t* context_length, SymmetricKeyType* out_key_type,
KeySize* out_key_size, WTPI_K1_SymmetricKey_Handle** out_key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10018)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, context_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
OPK_Unpack_uint8_t(msg, counter);
OPK_UnpackInPlace(msg, context, OPK_FromSizeTPtr(context_length));
OPK_Unpack_SymmetricKeyType(msg, out_key_type);
OPK_Unpack_KeySize(msg, out_key_size);
*out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_DeriveKeyFromKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle) {
uint32_t api_value = 10018; /* from _tee10018 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_WrapKey_Request(ODK_Message* msg, uint32_t* context,
WTPI_K1_SymmetricKey_Handle* key_handle,
SymmetricKeyType* key_type,
uint8_t** wrapped_key,
size_t* wrapped_key_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10019)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, wrapped_key_length);
OPK_Unpack_uint32_t(msg, context);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
OPK_Unpack_SymmetricKeyType(msg, key_type);
*wrapped_key = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtr(wrapped_key_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_WrapKey_Response(OEMCryptoResult result,
const uint8_t* wrapped_key,
size_t wrapped_key_length) {
uint32_t api_value = 10019; /* from _tee10019 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_size_t(&msg, &wrapped_key_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, wrapped_key, OPK_ToLengthType(wrapped_key_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_UnwrapIntoKeyHandle_Request(
ODK_Message* msg, uint32_t* context, uint8_t** wrapped_key,
size_t* wrapped_key_length, SymmetricKeyType* key_type,
WTPI_K1_SymmetricKey_Handle** out_key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10020)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, wrapped_key_length);
OPK_Unpack_uint32_t(msg, context);
OPK_UnpackInPlace(msg, wrapped_key, OPK_FromSizeTPtr(wrapped_key_length));
OPK_Unpack_SymmetricKeyType(msg, key_type);
*out_key_handle = (WTPI_K1_SymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_K1_SymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_UnwrapIntoKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle) {
uint32_t api_value = 10020; /* from _tee10020 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_K1_SymmetricKey_Handle(&msg, out_key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_K1_FreeKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10021)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key_handle);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_K1_FreeKeyHandle_Response(OEMCryptoResult result) {
uint32_t api_value = 10021; /* from _tee10021 */
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;
}
void OPK_Unpack_CreateAsymmetricKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10022)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, input_length);
OPK_UnpackInPlace(msg, input, OPK_FromSizeTPtr(input_length));
OPK_Unpack_AsymmetricKeyType(msg, key_type);
*key_handle = (WTPI_AsymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_AsymmetricKey_Handle));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Response(
OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle) {
uint32_t api_value = 10022; /* from _tee10022 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_AsymmetricKey_Handle(&msg, key_handle);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle,
uint32_t** allowed_schemes) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10023)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, input_length);
OPK_UnpackInPlace(msg, input, OPK_FromSizeTPtr(input_length));
OPK_Unpack_AsymmetricKeyType(msg, key_type);
*key_handle = (WTPI_AsymmetricKey_Handle*)OPK_UnpackAlloc(
msg, sizeof(WTPI_AsymmetricKey_Handle));
*allowed_schemes = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Response(
OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle,
const uint32_t* allowed_schemes) {
uint32_t api_value = 10023; /* from _tee10023 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_WTPI_AsymmetricKey_Handle(&msg, key_handle);
OPK_PackNullable_uint32_t(&msg, allowed_schemes);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_FreeAsymmetricKeyHandle_Request(
ODK_Message* msg, WTPI_AsymmetricKey_Handle* key_handle) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10024)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key_handle);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_FreeAsymmetricKeyHandle_Response(OEMCryptoResult result) {
uint32_t api_value = 10024; /* from _tee10024 */
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;
}
void OPK_Unpack_GetWrappedAsymmetricKeySize_Request(
ODK_Message* msg, size_t* enc_private_key_length,
AsymmetricKeyType* key_type, size_t** buffer_size) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10025)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, enc_private_key_length);
OPK_Unpack_AsymmetricKeyType(msg, key_type);
*buffer_size = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Response(
OEMCryptoResult result, const size_t* buffer_size) {
uint32_t api_value = 10025; /* from _tee10025 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_size_t(&msg, buffer_size);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_RSASign_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** message, size_t* message_length,
uint8_t** signature, size_t** signature_length,
RSA_Padding_Scheme* padding_scheme) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10026)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, message_length);
OPK_UnpackNullable_size_t(msg, signature_length);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, message, OPK_FromSizeTPtr(message_length));
*signature = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtrPtr(signature_length), sizeof(uint8_t));
OPK_Unpack_RSA_Padding_Scheme(msg, padding_scheme);
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_RSASign_Response(OEMCryptoResult result,
const uint8_t* signature,
const size_t* signature_length) {
uint32_t api_value = 10026; /* from _tee10026 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_PackNullable_size_t(&msg, signature_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, signature, OPK_FromSizeTPtr(signature_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_RSADecrypt_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** input, size_t* input_length,
uint8_t** out, size_t** out_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10027)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, input_length);
OPK_UnpackNullable_size_t(msg, out_length);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, input, OPK_FromSizeTPtr(input_length));
*out = (uint8_t*)OPK_UnpackAllocBuffer(msg, OPK_FromSizeTPtrPtr(out_length),
sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_RSADecrypt_Response(OEMCryptoResult result,
const uint8_t* out,
const size_t* out_length) {
uint32_t api_value = 10027; /* from _tee10027 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_PackNullable_size_t(&msg, out_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, out, OPK_FromSizeTPtr(out_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_ECCSign_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** message, size_t* message_length,
uint8_t** signature,
size_t** signature_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10028)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, message_length);
OPK_UnpackNullable_size_t(msg, signature_length);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, message, OPK_FromSizeTPtr(message_length));
*signature = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtrPtr(signature_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_ECCSign_Response(OEMCryptoResult result,
const uint8_t* signature,
const size_t* signature_length) {
uint32_t api_value = 10028; /* from _tee10028 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_PackNullable_size_t(&msg, signature_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, signature, OPK_FromSizeTPtr(signature_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** key_source,
size_t* key_source_length,
uint8_t** session_key,
size_t** session_key_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10029)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, key_source_length);
OPK_UnpackNullable_size_t(msg, session_key_length);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, key_source, OPK_FromSizeTPtr(key_source_length));
*session_key = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_FromSizeTPtrPtr(session_key_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_ECCDeriveSessionKey_Response(
OEMCryptoResult result, const uint8_t* session_key,
const size_t* session_key_length) {
uint32_t api_value = 10029; /* from _tee10029 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_PackNullable_size_t(&msg, session_key_length);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
OPK_PackMemory(&msg, session_key, OPK_FromSizeTPtr(session_key_length));
}
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
size_t** signature_length) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10030)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_WTPI_AsymmetricKey_Handle(msg, key);
*signature_length = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result,
const size_t* signature_length) {
uint32_t api_value = 10030; /* from _tee10030 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_size_t(&msg, signature_length);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10031)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
*initial_hash = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result,
const uint32_t* initial_hash) {
uint32_t api_value = 10031; /* from _tee10031 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_uint32_t(&msg, initial_hash);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in,
size_t* in_length, uint32_t* prev_crc,
uint32_t** new_crc) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10032)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_length);
OPK_UnpackInPlace(msg, in, OPK_FromSizeTPtr(in_length));
OPK_Unpack_uint32_t(msg, prev_crc);
*new_crc = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_Crc32Cont_Response(OEMCryptoResult result,
const uint32_t* new_crc) {
uint32_t api_value = 10032; /* from _tee10032 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_uint32_t(&msg, new_crc);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}
void OPK_Unpack_Crc32Cont_OutputBuffer_Request(
ODK_Message* msg, OPK_OutputBuffer** in, size_t* in_offset,
size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10033)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_length);
/* unpack object array with unpacker function OPK_Unpack_OPK_OutputBuffer */
ODK_Message* odk_message = msg;
void** address = (void**)in;
LengthType count = OPK_FromSizeTPtr(in_length);
size_t size = sizeof(OPK_OutputBuffer);
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_OPK_OutputBuffer(
odk_message, (OPK_OutputBuffer*)((*address) + size * i));
}
}
}
}
}
OPK_Unpack_size_t(msg, in_offset);
OPK_Unpack_uint32_t(msg, prev_crc);
*new_crc = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(uint32_t));
OPK_UnpackEOM(msg);
OPK_SharedBuffer_FinalizeUnpacking();
}
ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result,
const uint32_t* new_crc) {
uint32_t api_value = 10033; /* from _tee10033 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
OPK_PackNullable_uint32_t(&msg, new_crc);
OPK_PackEOM(&msg);
OPK_SharedBuffer_FinalizePacking();
return msg;
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright 2020 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 auto-generated, do not edit
*/
#ifndef OPK_TEE_SERIALIZER_H_
#define OPK_TEE_SERIALIZER_H_
#include "log_macros.h"
#include "opk_serialization_base.h"
#include "wtpi_crc32_interface.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
#ifdef __cplusplus
extern "C" {
#endif
void OPK_Unpack_PrepareGenerationNumber_Request(ODK_Message* msg);
ODK_Message OPK_Pack_PrepareGenerationNumber_Response(OEMCryptoResult result);
void OPK_Unpack_LoadGenerationNumber_Request(ODK_Message* msg,
uint64_t** value);
ODK_Message OPK_Pack_LoadGenerationNumber_Response(OEMCryptoResult result,
const uint64_t* value);
void OPK_Unpack_SaveGenerationNumber_Request(ODK_Message* msg, uint64_t* value);
ODK_Message OPK_Pack_SaveGenerationNumber_Response(OEMCryptoResult result);
void OPK_Unpack_K1_GetKeySize_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key_handle,
KeySize** size);
ODK_Message OPK_Pack_K1_GetKeySize_Response(OEMCryptoResult result,
const KeySize* size);
void OPK_Unpack_C1_AESCBCDecrypt_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle,
size_t* key_length, uint8_t** in_buffer, size_t* in_buffer_length,
uint8_t* iv, uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_AESCBCDecrypt_Response(OEMCryptoResult result,
size_t in_buffer_length,
const uint8_t* out_buffer);
void OPK_Unpack_C1_AESCBCEncrypt_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle,
uint8_t** in_buffer, size_t* in_buffer_length, uint8_t* iv,
uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_AESCBCEncrypt_Response(OEMCryptoResult result,
size_t in_buffer_length,
const uint8_t* out_buffer);
ODK_Message OPK_Pack_C1_HMAC_SHA256_Verify_Response(OEMCryptoResult result);
void OPK_Unpack_C1_CopyToOutputBuffer_Request(ODK_Message* msg, uint8_t** input,
size_t* input_length,
OPK_OutputBuffer** out,
size_t* output_offset);
ODK_Message OPK_Pack_C1_CopyToOutputBuffer_Response(OEMCryptoResult result);
void OPK_Unpack_C1_RandomBytes_Request(ODK_Message* msg, uint8_t** out,
size_t* out_length);
ODK_Message OPK_Pack_C1_RandomBytes_Response(OEMCryptoResult result,
const uint8_t* out,
size_t out_length);
void OPK_Unpack_K1_InitializeKeyManagement_Request(ODK_Message* msg);
ODK_Message OPK_Pack_K1_InitializeKeyManagement_Response(
OEMCryptoResult result);
void OPK_Unpack_K1_TerminateKeyManagement_Request(ODK_Message* msg);
ODK_Message OPK_Pack_K1_TerminateKeyManagement_Response(OEMCryptoResult result);
void OPK_Unpack_K1_CreateKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_CreateKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_DeriveDeviceKeyIntoHandle_Request(
ODK_Message* msg, uint32_t* context, SymmetricKeyType* out_key_type,
WTPI_K1_SymmetricKey_Handle** out_key_handle, KeySize* out_key_size);
ODK_Message OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle,
uint8_t** enc_key, size_t* enc_key_length, uint8_t* iv,
SymmetricKeyType* key_type, WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* decrypt_key_handle,
uint8_t** enc_mac_keys, size_t* enc_mac_keys_length, uint8_t* iv,
WTPI_K1_SymmetricKey_Handle** out_mac_key_server,
WTPI_K1_SymmetricKey_Handle** out_mac_key_client);
ODK_Message OPK_Pack_K1_AESDecryptAndCreateKeyHandleForMacKeys_Response(
OEMCryptoResult result,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_server,
const WTPI_K1_SymmetricKey_Handle* out_mac_key_client);
void OPK_Unpack_K1_DeriveKeyFromKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle, uint8_t* counter,
uint8_t** context, size_t* context_length, SymmetricKeyType* out_key_type,
KeySize* out_key_size, WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_DeriveKeyFromKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_WrapKey_Request(ODK_Message* msg, uint32_t* context,
WTPI_K1_SymmetricKey_Handle* key_handle,
SymmetricKeyType* key_type,
uint8_t** wrapped_key,
size_t* wrapped_key_length);
ODK_Message OPK_Pack_K1_WrapKey_Response(OEMCryptoResult result,
const uint8_t* wrapped_key,
size_t wrapped_key_length);
void OPK_Unpack_K1_UnwrapIntoKeyHandle_Request(
ODK_Message* msg, uint32_t* context, uint8_t** wrapped_key,
size_t* wrapped_key_length, SymmetricKeyType* key_type,
WTPI_K1_SymmetricKey_Handle** out_key_handle);
ODK_Message OPK_Pack_K1_UnwrapIntoKeyHandle_Response(
OEMCryptoResult result, const WTPI_K1_SymmetricKey_Handle* out_key_handle);
void OPK_Unpack_K1_FreeKeyHandle_Request(
ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key_handle);
ODK_Message OPK_Pack_K1_FreeKeyHandle_Response(OEMCryptoResult result);
void OPK_Unpack_CreateAsymmetricKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle);
ODK_Message OPK_Pack_CreateAsymmetricKeyHandle_Response(
OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle);
void OPK_Unpack_UnwrapIntoAsymmetricKeyHandle_Request(
ODK_Message* msg, uint8_t** input, size_t* input_length,
AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle** key_handle,
uint32_t** allowed_schemes);
ODK_Message OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Response(
OEMCryptoResult result, const WTPI_AsymmetricKey_Handle* key_handle,
const uint32_t* allowed_schemes);
void OPK_Unpack_FreeAsymmetricKeyHandle_Request(
ODK_Message* msg, WTPI_AsymmetricKey_Handle* key_handle);
ODK_Message OPK_Pack_FreeAsymmetricKeyHandle_Response(OEMCryptoResult result);
void OPK_Unpack_GetWrappedAsymmetricKeySize_Request(
ODK_Message* msg, size_t* enc_private_key_length,
AsymmetricKeyType* key_type, size_t** buffer_size);
ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Response(
OEMCryptoResult result, const size_t* buffer_size);
void OPK_Unpack_RSASign_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** message, size_t* message_length,
uint8_t** signature, size_t** signature_length,
RSA_Padding_Scheme* padding_scheme);
ODK_Message OPK_Pack_RSASign_Response(OEMCryptoResult result,
const uint8_t* signature,
const size_t* signature_length);
void OPK_Unpack_RSADecrypt_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** input, size_t* input_length,
uint8_t** out, size_t** out_length);
ODK_Message OPK_Pack_RSADecrypt_Response(OEMCryptoResult result,
const uint8_t* out,
const size_t* out_length);
void OPK_Unpack_ECCSign_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** message, size_t* message_length,
uint8_t** signature, size_t** signature_length);
ODK_Message OPK_Pack_ECCSign_Response(OEMCryptoResult result,
const uint8_t* signature,
const size_t* signature_length);
void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
uint8_t** key_source,
size_t* key_source_length,
uint8_t** session_key,
size_t** session_key_length);
ODK_Message OPK_Pack_ECCDeriveSessionKey_Response(
OEMCryptoResult result, const uint8_t* session_key,
const size_t* session_key_length);
void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg,
WTPI_AsymmetricKey_Handle* key,
size_t** signature_length);
ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result,
const size_t* signature_length);
void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash);
ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result,
const uint32_t* initial_hash);
void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in,
size_t* in_length, uint32_t* prev_crc,
uint32_t** new_crc);
ODK_Message OPK_Pack_Crc32Cont_Response(OEMCryptoResult result,
const uint32_t* new_crc);
void OPK_Unpack_Crc32Cont_OutputBuffer_Request(
ODK_Message* msg, OPK_OutputBuffer** in, size_t* in_offset,
size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc);
ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result,
const uint32_t* new_crc);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPK_TEE_SERIALIZER_H_ */

View File

@@ -0,0 +1,54 @@
#
# Builds the static library opk_tee.a from the
# generated sources based on oemcrypto_wtpi_macros.h.
#
{
'includes': [
'../settings.gypi'
],
'target_defaults': {
'variables': {
# If |enable_code_generator| is true, the GEN_* files will be
# updated if they are out of date.
'enable_code_generator%': 'false',
},
},
'targets': [
{
'target_name': 'opk_tee_wtpi_test',
'type': 'static_library',
'toolsets': ['target'],
'include_dirs': [
'<(serialization_dir)/tee/include',
'<(wtpi_dir)',
'<(wtpi_test_dir)/generator',
],
'sources': [
'GEN_dispatcher.c',
'GEN_tee_serializer.c',
'tee_special_cases.c',
'<(common_dir)/GEN_common_serializer.c',
'<(common_dir)/common_special_cases.c',
'<(odk_dir)/src/odk_message.c',
'<(odk_dir)/src/odk_overflow.c',
'<(serialization_common_dir)/bump_allocator.c',
'<(serialization_common_dir)/length_types.c',
'<(serialization_common_dir)/log_macros.c',
'<(serialization_common_dir)/marshaller_base.c',
'<(serialization_common_dir)/opk_init.c',
'<(serialization_common_dir)/opk_serialization_base.c',
'<(serialization_common_dir)/shared_buffer_allocator.c',
],
'conditions': [
['enable_code_generator=="true"', {
'dependencies': [
'<(wtpi_test_dir)/generator/make_source.gyp:make_common_serializer_src',
'<(wtpi_test_dir)/generator/make_source.gyp:make_dispatcher_src',
'<(wtpi_test_dir)/generator/make_source.gyp:make_tee_serializer_src',
],
}
]
]
}
]
}

View File

@@ -0,0 +1,194 @@
/*
* 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 "tee_special_cases.h"
#include <string.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 "oemcrypto_wall_clock.h"
#include "opk_dispatcher.h"
#include "shared_buffer_allocator.h"
#include "tos_shared_memory_interface.h"
#include "tos_transport_interface.h"
#include "wtpi_generation_number_interface.h"
void OPK_Init_WTPI_K1_SymmetricKey_Handle(WTPI_K1_SymmetricKey_Handle* obj) {
if (obj) {
memset(obj, 0, sizeof(WTPI_K1_SymmetricKey_Handle));
}
}
void OPK_Init_OPK_OutputBuffer(OPK_OutputBuffer* obj) {
if (obj) {
memset(obj, 0, sizeof(OPK_OutputBuffer));
}
}
void OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
OEMCrypto_CENCEncryptPatternDesc* obj) {
if (obj) {
memset(obj, 0, sizeof(OEMCrypto_CENCEncryptPatternDesc));
}
}
void OPK_Init_SymmetricKeyType(SymmetricKeyType* obj) {
if (obj) {
memset(obj, 0, sizeof(SymmetricKeyType));
}
}
void OPK_Init_AsymmetricKeyType(AsymmetricKeyType* obj) {
if (obj) {
memset(obj, 0, sizeof(AsymmetricKeyType));
}
}
void OPK_Init_WTPI_AsymmetricKey_Handle(WTPI_AsymmetricKey_Handle* obj) {
if (obj) {
memset(obj, 0, sizeof(WTPI_AsymmetricKey_Handle));
}
}
void OPK_Init_RSA_Padding_Scheme(RSA_Padding_Scheme* obj) {
if (obj) {
memset(obj, 0, sizeof(RSA_Padding_Scheme));
}
}
void OPK_Init_KeySize(KeySize* obj) {
if (obj) {
memset(obj, 0, sizeof(KeySize));
}
}
void OPK_Unpack_WTPI_K1_SymmetricKey_Handle(ODK_Message* message,
WTPI_K1_SymmetricKey_Handle* value);
void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** message,
size_t* message_length,
uint8_t** signature) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10009)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, message_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, message, OPK_FromSizeTPtr(message_length));
size_t signature_len = 32;
OPK_UnpackInPlace(msg, signature, OPK_FromSizeTPtr(&signature_len));
OPK_UnpackEOM(msg);
}
void OPK_Unpack_C1_SHA256_Request(ODK_Message* msg, uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
LOGE("TEE special case 10007 OPK_Unpack_C1_SHA256_Request");
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10007) {
LOGE("OPK_Unpack_C1_SHA256_Request api_value = %u", api_value);
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
}
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_buffer_length);
OPK_UnpackInPlace(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length));
size_t out_length = 32;
*out_buffer = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_ToLengthType(out_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
}
ODK_Message OPK_Pack_C1_SHA256_Response(OEMCryptoResult result,
const uint8_t* out_buffer) {
LOGE("TEE special case 10007 OPK_Pack_C1_SHA256_Response");
uint32_t api_value = 10007; /* from _tee10007 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
size_t out_length = 32;
OPK_PackMemory(&msg, out_buffer, OPK_ToLengthType(out_length));
}
OPK_PackEOM(&msg);
return msg;
}
void OPK_Unpack_C1_HMAC_SHA256_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10008)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_buffer_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length));
size_t out_length = 32;
*out_buffer = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_ToLengthType(out_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
}
ODK_Message OPK_Pack_C1_HMAC_SHA256_Response(OEMCryptoResult result,
const uint8_t* out_buffer) {
uint32_t api_value = 10008; /* from _tee10008 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
size_t out_length = 32;
OPK_PackMemory(&msg, out_buffer, OPK_ToLengthType(out_length));
}
OPK_PackEOM(&msg);
return msg;
}
void OPK_Unpack_C1_HMAC_SHA1_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer) {
uint32_t api_value = UINT32_MAX;
OPK_Unpack_uint32_t(msg, &api_value);
if (api_value != 10006)
ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR);
uint64_t timestamp;
OPK_Unpack_uint64_t(msg, &timestamp);
OPK_Unpack_size_t(msg, in_buffer_length);
OPK_Unpack_WTPI_K1_SymmetricKey_Handle(msg, key);
OPK_UnpackInPlace(msg, in_buffer, OPK_FromSizeTPtr(in_buffer_length));
size_t out_length = 20;
*out_buffer = (uint8_t*)OPK_UnpackAllocBuffer(
msg, OPK_ToLengthType(out_length), sizeof(uint8_t));
OPK_UnpackEOM(msg);
}
ODK_Message OPK_Pack_C1_HMAC_SHA1_Response(OEMCryptoResult result,
const uint8_t* out_buffer) {
uint32_t api_value = 10006; /* from _tee10006 */
ODK_Message msg = TOS_Transport_GetResponse();
OPK_Pack_uint32_t(&msg, &api_value);
OPK_Pack_uint32_t(&msg, &result);
if (SuccessResult(result)) {
size_t out_length = 20;
OPK_PackMemory(&msg, out_buffer, OPK_ToLengthType(out_length));
}
OPK_PackEOM(&msg);
return msg;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2020 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_TEE_SPECIAL_CASES_H_
#define WTPI_TEST_TEE_SPECIAL_CASES_H_
#include "odk_message.h"
#include "wtpi_crypto_and_key_management_interface_layer1.h"
#include "wtpi_crypto_asymmetric_interface.h"
void OPK_Init_WTPI_K1_SymmetricKey_Handle(WTPI_K1_SymmetricKey_Handle* obj);
void OPK_Init_OPK_OutputBuffer(OPK_OutputBuffer* obj);
void OPK_Init_OEMCrypto_CENCEncryptPatternDesc(
OEMCrypto_CENCEncryptPatternDesc* obj);
void OPK_Init_SymmetricKeyType(SymmetricKeyType* obj);
void OPK_Init_AsymmetricKeyType(AsymmetricKeyType* obj);
void OPK_Init_WTPI_AsymmetricKey_Handle(WTPI_AsymmetricKey_Handle* obj);
void OPK_Init_RSA_Padding_Scheme(RSA_Padding_Scheme* obj);
void OPK_Init_KeySize(KeySize* obj);
void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** message,
size_t* message_length,
uint8_t** signature);
void OPK_Unpack_C1_SHA256_Request(ODK_Message* msg, uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_SHA256_Response(OEMCryptoResult result,
const uint8_t* out_buffer);
void OPK_Unpack_C1_HMAC_SHA256_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer);
ODK_Message OPK_Pack_C1_HMAC_SHA256_Response(OEMCryptoResult result,
const uint8_t* out_buffer);
ODK_Message OPK_Pack_C1_HMAC_SHA1_Response(OEMCryptoResult result,
const uint8_t* out_buffer);
void OPK_Unpack_C1_HMAC_SHA1_Request(ODK_Message* msg,
WTPI_K1_SymmetricKey_Handle* key,
uint8_t** in_buffer,
size_t* in_buffer_length,
uint8_t** out_buffer);
#endif

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
* source code may only be used and distributed under the Widevine
* License Agreement.
*/
/*
* Generated from oemcrypto/test/test_rsa_key.der
*
* xxd -i test_rsa_key.der > test_rsa_key.cpp
*
* This is a PKCS8 RSA key encoded in DER format.
*/
#include "stdint.h"
uint8_t test_rsa_key_der[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x5e, 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, 0xd5, 0xde, 0x33, 0x63,
0xd8, 0xb8, 0xac, 0x97, 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, 0x46, 0xf5, 0xca, 0x2d,
0x8b, 0x3a, 0x7e, 0xdc, 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, 0xc1, 0x6b, 0x78, 0x04,
0x4e, 0x8e, 0x79, 0xf9, 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, 0xa7, 0x79, 0x5c, 0x7a,
0x81, 0xd1, 0x71, 0xe7, 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, 0x0e, 0x97, 0x8d, 0x89,
0x6e, 0xf1, 0xe8, 0x88, 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, 0xb6, 0xda, 0xc6, 0x24,
0x5a, 0xd0, 0x37, 0x14, 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, 0x68, 0x71, 0x17, 0x66,
0x12, 0x1a, 0x87, 0x27, 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, 0x13, 0x86, 0x9c, 0x79,
0xd0, 0xb7, 0xb6, 0x64, 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, 0x70, 0x98, 0x0f, 0xee,
0xa8, 0x96, 0x07, 0x5f, 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, 0x96, 0xa9, 0x03, 0x17,
0xbb, 0x4e, 0xc9, 0x21, 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, 0x81, 0x81, 0x00, 0xcf,
0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
0x33, 0xe0, 0xdb, 0x03};
/*
* Generated with openssl:
* `echo 'Hello world!' | openssl pkeyutl -inkey test_rsa_key.der -keyform DER
* -encrypt -pkeyopt rsa_padding_mode:oaep -pkeyopt`
*/
uint8_t hello_world_encrypted[] = {
0x81, 0xf5, 0x07, 0xe5, 0x3f, 0x18, 0xab, 0x88, 0x28, 0xac, 0x47, 0x88,
0x93, 0xe0, 0x80, 0x90, 0x1e, 0x5b, 0x1a, 0x8f, 0xbc, 0xe1, 0xe7, 0xe0,
0xd3, 0x42, 0x10, 0x23, 0x5f, 0x0a, 0x2f, 0x81, 0x71, 0x4a, 0xcb, 0x28,
0x64, 0x08, 0x15, 0x0e, 0xf1, 0x15, 0x52, 0x5e, 0xc3, 0xd2, 0x21, 0x75,
0x58, 0xfe, 0x8f, 0x76, 0x6e, 0x6a, 0x29, 0x94, 0xd5, 0x40, 0xd4, 0x29,
0x05, 0x47, 0x37, 0x21, 0x3c, 0x4a, 0xa0, 0xcc, 0x24, 0xed, 0x6b, 0x24,
0xc3, 0x4b, 0xee, 0xb6, 0x90, 0x3f, 0xe0, 0x74, 0x8b, 0x4d, 0xc1, 0x58,
0x4f, 0xfa, 0x58, 0xf0, 0x76, 0x29, 0xe4, 0x43, 0x2e, 0x0f, 0xc0, 0x68,
0x1b, 0x61, 0xba, 0x38, 0xea, 0x43, 0xc4, 0xa3, 0x08, 0xbd, 0x2b, 0xbe,
0x8e, 0x39, 0xf5, 0x3a, 0x81, 0x67, 0x5f, 0x20, 0xc9, 0x90, 0x66, 0x0e,
0xaf, 0xbc, 0xd8, 0xb3, 0xe0, 0xd8, 0xdc, 0x02, 0x42, 0x3b, 0x1a, 0xa2,
0x33, 0x0e, 0x5f, 0x6f, 0x6d, 0x83, 0x46, 0x89, 0x05, 0xa6, 0x2a, 0xe2,
0xec, 0x00, 0xaf, 0xb0, 0xc9, 0xb7, 0x96, 0x93, 0x89, 0xc1, 0x55, 0x7d,
0xc2, 0x83, 0xfa, 0x15, 0xf2, 0xee, 0x5b, 0x30, 0xc7, 0xcb, 0x00, 0x72,
0xbc, 0xe5, 0x30, 0xec, 0x4b, 0x94, 0x07, 0x1a, 0x4e, 0xf1, 0x59, 0xb1,
0xfb, 0x1c, 0xd7, 0x75, 0x58, 0xde, 0xbb, 0xb3, 0x46, 0x8e, 0x2a, 0xf0,
0x6e, 0x16, 0x3a, 0xb6, 0x4d, 0x0a, 0x84, 0x4d, 0xf5, 0xb8, 0xb4, 0x29,
0x57, 0x2d, 0x0c, 0xd6, 0x4d, 0x39, 0x98, 0x67, 0xec, 0x11, 0x51, 0xa9,
0xdb, 0x91, 0x52, 0x6a, 0x92, 0x0e, 0x31, 0x24, 0xe2, 0x7b, 0xcb, 0xac,
0xfe, 0xba, 0x18, 0x86, 0x8e, 0x68, 0xf9, 0x83, 0x82, 0x2c, 0x3c, 0x88,
0x7f, 0x77, 0x27, 0x16, 0x51, 0x0c, 0x8b, 0x8e, 0x26, 0x60, 0xf6, 0x96,
0xf9, 0xdd, 0x37, 0x40};

View File

@@ -0,0 +1,50 @@
{
'includes': {
'settings.gypi',
},
'variables': {
'platform_specific_dir': '<(DEPTH)/linux/src',
'opk_ree': 'ree/ree.gyp:opk_ree',
},
'target_defaults': {
'include_dirs': [
'.',
'<(wtpi_dir)',
'<(third_party_dir)/googletest/googletest/include',
'<(util_dir)/include',
],
},
'targets': [
{
'target_name': 'wtpi_test',
'type': 'executable',
'toolsets': ['target'],
'sources': [
'wtpi_test_main.cpp',
],
'dependencies': [
'<(opk_ree)',
'<(third_party_dir)/googletest.gyp:gtest',
'wtpi_test_lib',
],
'libraries': ['-lrt', '-lpthread', '-ldl'],
'ldflags': [
'-Wl,--whole-archive',
'libwtpi_test_lib.a',
'-Wl,--no-whole-archive',
],
},
{
'target_name': 'wtpi_test_lib',
'type': 'static_library',
'toolsets': ['target'],
'standalone_static_library': 1,
'sources': [
'generation_number_interface_test.cpp',
'crypto_test.cpp',
'test_rsa_key.cpp',
'<(DEPTH)/linux/src/log.cpp',
],
},
]
}

View File

@@ -0,0 +1,10 @@
// 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 <gtest/gtest.h>
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

Some files were not shown because too many files have changed in this diff Show More