1*ad194957SYi Chou // SPDX-License-Identifier: BSD-2-Clause
2*ad194957SYi Chou /*
3*ad194957SYi Chou * Copyright (c) 2023, The ChromiumOS Authors
4*ad194957SYi Chou */
5*ad194957SYi Chou
6*ad194957SYi Chou #include <compiler.h>
7*ad194957SYi Chou #include <initcall.h>
8*ad194957SYi Chou #include <kernel/dt.h>
9*ad194957SYi Chou #include <kernel/pseudo_ta.h>
10*ad194957SYi Chou #include <kernel/tee_ta_manager.h>
11*ad194957SYi Chou #include <kernel/ts_manager.h>
12*ad194957SYi Chou #include <kernel/user_ta.h>
13*ad194957SYi Chou #include <libfdt.h>
14*ad194957SYi Chou #include <pta_widevine.h>
15*ad194957SYi Chou #include <stdint.h>
16*ad194957SYi Chou #include <string.h>
17*ad194957SYi Chou #include <tee_api.h>
18*ad194957SYi Chou #include <util.h>
19*ad194957SYi Chou
20*ad194957SYi Chou #define PTA_NAME "widevine.pta"
21*ad194957SYi Chou
22*ad194957SYi Chou #define TPM_AUTH_PUB_MAX_SIZE 1024
23*ad194957SYi Chou #define WIDEVINE_PRIV_MAX_SIZE 32
24*ad194957SYi Chou
25*ad194957SYi Chou #define CROS_HWSEC_TA_UUID \
26*ad194957SYi Chou { \
27*ad194957SYi Chou 0xed800e33, 0x3c58, 0x4cae, \
28*ad194957SYi Chou { \
29*ad194957SYi Chou 0xa7, 0xc0, 0xfd, 0x16, 0x0e, 0x35, 0xe0, 0x0d \
30*ad194957SYi Chou } \
31*ad194957SYi Chou }
32*ad194957SYi Chou #define CROS_HDCP_PROV4_TA_UUID \
33*ad194957SYi Chou { \
34*ad194957SYi Chou 0x0feb839c, 0xee25, 0x4920, \
35*ad194957SYi Chou { \
36*ad194957SYi Chou 0x8e, 0xe3, 0xac, 0x8d, 0xaa, 0x86, 0x0d, 0x3b \
37*ad194957SYi Chou } \
38*ad194957SYi Chou }
39*ad194957SYi Chou #define TA_OPTEE_OEMCRYPTO_UUID \
40*ad194957SYi Chou { \
41*ad194957SYi Chou 0xa92d116c, 0xce27, 0x4917, \
42*ad194957SYi Chou { \
43*ad194957SYi Chou 0xb3, 0x0c, 0x4a, 0x41, 0x6e, 0x2d, 0x93, 0x51 \
44*ad194957SYi Chou } \
45*ad194957SYi Chou }
46*ad194957SYi Chou
47*ad194957SYi Chou static const TEE_UUID allowed_ta_uuids[3] = {
48*ad194957SYi Chou CROS_HWSEC_TA_UUID,
49*ad194957SYi Chou CROS_HDCP_PROV4_TA_UUID,
50*ad194957SYi Chou TA_OPTEE_OEMCRYPTO_UUID,
51*ad194957SYi Chou };
52*ad194957SYi Chou
53*ad194957SYi Chou /*
54*ad194957SYi Chou * The TPM auth public key. Used to communicate with the TPM from OP-TEE.
55*ad194957SYi Chou * The format of data should be TPM2B_PUBLIC.
56*ad194957SYi Chou * For more information, please reference the 12.2.5 section:
57*ad194957SYi Chou * https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part2_Structures_pub.pdf
58*ad194957SYi Chou */
59*ad194957SYi Chou static uint8_t tpm_auth_pub[TPM_AUTH_PUB_MAX_SIZE];
60*ad194957SYi Chou static uint32_t tpm_auth_pub_size;
61*ad194957SYi Chou
62*ad194957SYi Chou /*
63*ad194957SYi Chou * The Widevine root of trust secret. Used to sign the widevine
64*ad194957SYi Chou * requests in OP-TEE. The value is an ECC NIST P-256 scalar.
65*ad194957SYi Chou * For more information, please reference the G.1.2 section:
66*ad194957SYi Chou * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf
67*ad194957SYi Chou */
68*ad194957SYi Chou static uint8_t widevine_priv[WIDEVINE_PRIV_MAX_SIZE];
69*ad194957SYi Chou static uint32_t widevine_priv_size;
70*ad194957SYi Chou
init_widevine_dt_data(void)71*ad194957SYi Chou static TEE_Result init_widevine_dt_data(void)
72*ad194957SYi Chou {
73*ad194957SYi Chou int node = 0;
74*ad194957SYi Chou int len = 0;
75*ad194957SYi Chou void *fdt = NULL;
76*ad194957SYi Chou const void *value = NULL;
77*ad194957SYi Chou
78*ad194957SYi Chou fdt = get_secure_dt();
79*ad194957SYi Chou if (!fdt)
80*ad194957SYi Chou return TEE_ERROR_NO_DATA;
81*ad194957SYi Chou
82*ad194957SYi Chou node = fdt_path_offset(fdt, "/options/op-tee/widevine");
83*ad194957SYi Chou if (node < 0)
84*ad194957SYi Chou return TEE_ERROR_ITEM_NOT_FOUND;
85*ad194957SYi Chou
86*ad194957SYi Chou value = fdt_getprop(fdt, node, "tcg,tpm-auth-public-key", &len);
87*ad194957SYi Chou if (!value)
88*ad194957SYi Chou return TEE_ERROR_ITEM_NOT_FOUND;
89*ad194957SYi Chou
90*ad194957SYi Chou if (len > TPM_AUTH_PUB_MAX_SIZE)
91*ad194957SYi Chou return TEE_ERROR_OVERFLOW;
92*ad194957SYi Chou
93*ad194957SYi Chou memcpy(tpm_auth_pub, value, len);
94*ad194957SYi Chou tpm_auth_pub_size = len;
95*ad194957SYi Chou
96*ad194957SYi Chou value = fdt_getprop(fdt, node, "google,widevine-root-of-trust-ecc-p256",
97*ad194957SYi Chou &len);
98*ad194957SYi Chou if (!value)
99*ad194957SYi Chou return TEE_ERROR_ITEM_NOT_FOUND;
100*ad194957SYi Chou
101*ad194957SYi Chou if (len > WIDEVINE_PRIV_MAX_SIZE)
102*ad194957SYi Chou return TEE_ERROR_OVERFLOW;
103*ad194957SYi Chou
104*ad194957SYi Chou memcpy(widevine_priv, value, len);
105*ad194957SYi Chou widevine_priv_size = len;
106*ad194957SYi Chou
107*ad194957SYi Chou return TEE_SUCCESS;
108*ad194957SYi Chou }
109*ad194957SYi Chou
110*ad194957SYi Chou service_init(init_widevine_dt_data);
111*ad194957SYi Chou
open_session(uint32_t param_types __unused,TEE_Param params[TEE_NUM_PARAMS]__unused,void ** sess_ctx __unused)112*ad194957SYi Chou static TEE_Result open_session(uint32_t param_types __unused,
113*ad194957SYi Chou TEE_Param params[TEE_NUM_PARAMS] __unused,
114*ad194957SYi Chou void **sess_ctx __unused)
115*ad194957SYi Chou {
116*ad194957SYi Chou size_t i = 0;
117*ad194957SYi Chou struct ts_session *session = ts_get_calling_session();
118*ad194957SYi Chou
119*ad194957SYi Chou /* Make sure we are called from a TA */
120*ad194957SYi Chou if (!is_user_ta_ctx(session->ctx))
121*ad194957SYi Chou return TEE_ERROR_ACCESS_DENIED;
122*ad194957SYi Chou
123*ad194957SYi Chou /* Make sure we are called from an allowed TA */
124*ad194957SYi Chou for (i = 0; i < ARRAY_SIZE(allowed_ta_uuids); i++)
125*ad194957SYi Chou if (memcmp(&session->ctx->uuid, &allowed_ta_uuids[i],
126*ad194957SYi Chou sizeof(TEE_UUID)) == 0)
127*ad194957SYi Chou return TEE_SUCCESS;
128*ad194957SYi Chou
129*ad194957SYi Chou return TEE_ERROR_ACCESS_DENIED;
130*ad194957SYi Chou }
131*ad194957SYi Chou
get_dt_data(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS],uint32_t cmd)132*ad194957SYi Chou static TEE_Result get_dt_data(uint32_t ptypes, TEE_Param params[TEE_NUM_PARAMS],
133*ad194957SYi Chou uint32_t cmd)
134*ad194957SYi Chou {
135*ad194957SYi Chou uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
136*ad194957SYi Chou TEE_PARAM_TYPE_NONE,
137*ad194957SYi Chou TEE_PARAM_TYPE_NONE,
138*ad194957SYi Chou TEE_PARAM_TYPE_NONE);
139*ad194957SYi Chou uint8_t *data = NULL;
140*ad194957SYi Chou uint32_t data_length = 0;
141*ad194957SYi Chou
142*ad194957SYi Chou if (exp_pt != ptypes)
143*ad194957SYi Chou return TEE_ERROR_BAD_PARAMETERS;
144*ad194957SYi Chou
145*ad194957SYi Chou if (cmd == PTA_WIDEVINE_GET_TPM_PUBKEY) {
146*ad194957SYi Chou data = tpm_auth_pub;
147*ad194957SYi Chou data_length = tpm_auth_pub_size;
148*ad194957SYi Chou } else if (cmd == PTA_WIDEVINE_GET_WIDEVINE_PRIVKEY) {
149*ad194957SYi Chou data = widevine_priv;
150*ad194957SYi Chou data_length = widevine_priv_size;
151*ad194957SYi Chou } else {
152*ad194957SYi Chou return TEE_ERROR_NOT_IMPLEMENTED;
153*ad194957SYi Chou }
154*ad194957SYi Chou
155*ad194957SYi Chou if (data_length == 0)
156*ad194957SYi Chou return TEE_ERROR_NO_DATA;
157*ad194957SYi Chou
158*ad194957SYi Chou if (data_length > params[0].memref.size) {
159*ad194957SYi Chou params[0].memref.size = data_length;
160*ad194957SYi Chou return TEE_ERROR_SHORT_BUFFER;
161*ad194957SYi Chou }
162*ad194957SYi Chou
163*ad194957SYi Chou params[0].memref.size = data_length;
164*ad194957SYi Chou memcpy(params[0].memref.buffer, data, data_length);
165*ad194957SYi Chou
166*ad194957SYi Chou return TEE_SUCCESS;
167*ad194957SYi Chou }
168*ad194957SYi Chou
169*ad194957SYi Chou /*
170*ad194957SYi Chou * Trusted Application Entry Points
171*ad194957SYi Chou */
invoke_command(void * psess __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])172*ad194957SYi Chou static TEE_Result invoke_command(void *psess __unused, uint32_t cmd,
173*ad194957SYi Chou uint32_t ptypes,
174*ad194957SYi Chou TEE_Param params[TEE_NUM_PARAMS])
175*ad194957SYi Chou {
176*ad194957SYi Chou return get_dt_data(ptypes, params, cmd);
177*ad194957SYi Chou }
178*ad194957SYi Chou
179*ad194957SYi Chou pseudo_ta_register(.uuid = PTA_WIDEVINE_UUID, .name = PTA_NAME,
180*ad194957SYi Chou .flags = PTA_DEFAULT_FLAGS,
181*ad194957SYi Chou .open_session_entry_point = open_session,
182*ad194957SYi Chou .invoke_command_entry_point = invoke_command);
183