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