1 /* 2 * Copyright (c) 2024-2025, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 */ 7 8 #include <qcbor/qcbor_decode.h> 9 #include <qcbor/qcbor_encode.h> 10 #include <qcbor/qcbor_spiffy_decode.h> 11 12 #include <common/debug.h> 13 #include <dice.h> 14 #include <dice_protection_environment.h> 15 #include <psa/client.h> 16 #include <psa_manifest/sid.h> 17 18 enum dpe_command_id_t { 19 /* Standard commands */ 20 DPE_GET_PROFILE = 1, 21 DPE_OPEN_SESSION = 2, 22 DPE_CLOSE_SESSION = 3, 23 DPE_SYNC_SESSION = 4, 24 DPE_EXPORT_SESSION = 5, 25 DPE_IMPORT_SESSION = 6, 26 DPE_INITIALIZE_CONTEXT = 7, 27 DPE_DERIVE_CONTEXT = 8, 28 DPE_CERTIFY_KEY = 9, 29 DPE_SIGN = 10, 30 DPE_SEAL = 11, 31 DPE_UNSEAL = 12, 32 DPE_DERIVE_SEALING_PUBLIC_KEY = 13, 33 DPE_ROTATE_CONTEXT_HANDLE = 14, 34 DPE_DESTROY_CONTEXT = 15, 35 }; 36 37 enum dice_input_labels_t { 38 DICE_CODE_HASH = 1, 39 DICE_CODE_DESCRIPTOR = 2, 40 DICE_CONFIG_TYPE = 3, 41 DICE_CONFIG_VALUE = 4, 42 DICE_CONFIG_DESCRIPTOR = 5, 43 DICE_AUTHORITY_HASH = 6, 44 DICE_AUTHORITY_DESCRIPTOR = 7, 45 DICE_MODE = 8, 46 DICE_HIDDEN = 9, 47 }; 48 49 enum dpe_derive_context_input_labels_t { 50 DPE_DERIVE_CONTEXT_CONTEXT_HANDLE = 1, 51 DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT = 2, 52 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE = 3, 53 DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE = 4, 54 DPE_DERIVE_CONTEXT_NEW_SESSION_INITIATOR_HANDSHAKE = 5, 55 DPE_DERIVE_CONTEXT_INPUT_DATA = 6, 56 DPE_DERIVE_CONTEXT_INTERNAL_INPUTS = 7, 57 DPE_DERIVE_CONTEXT_TARGET_LOCALITY = 8, 58 DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE = 9, 59 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT = 10, 60 DPE_DERIVE_CONTEXT_EXPORT_CDI = 11, 61 /* enum values 256 and onwards are reserved for custom arguments */ 62 DPE_DERIVE_CONTEXT_CERT_ID = 256, 63 }; 64 65 enum dpe_derive_context_output_labels_t { 66 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE = 1, 67 DPE_DERIVE_CONTEXT_NEW_SESSION_RESPONDER_HANDSHAKE = 2, 68 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE = 3, 69 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE = 4, 70 DPE_DERIVE_CONTEXT_EXPORTED_CDI = 5, 71 }; 72 73 struct derive_context_input_t { 74 int context_handle; 75 uint32_t cert_id; 76 bool retain_parent_context; 77 bool allow_new_context_to_derive; 78 bool create_certificate; 79 const DiceInputValues *dice_inputs; 80 int32_t target_locality; 81 bool return_certificate; 82 bool allow_new_context_to_export; 83 bool export_cdi; 84 }; 85 86 struct derive_context_output_t { 87 int new_context_handle; 88 int new_parent_context_handle; 89 const uint8_t *new_certificate; 90 size_t new_certificate_size; 91 const uint8_t *exported_cdi; 92 size_t exported_cdi_size; 93 }; 94 95 static void encode_dice_inputs(QCBOREncodeContext *encode_ctx, 96 const DiceInputValues *input) 97 { 98 /* Wrap the DICE inputs into a byte string */ 99 QCBOREncode_BstrWrapInMapN(encode_ctx, DPE_DERIVE_CONTEXT_INPUT_DATA); 100 101 /* Inside the byte string the DICE inputs are encoded as a map */ 102 QCBOREncode_OpenMap(encode_ctx); 103 104 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_HASH, 105 (UsefulBufC) { input->code_hash, 106 sizeof(input->code_hash) }); 107 108 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CODE_DESCRIPTOR, 109 (UsefulBufC) { input->code_descriptor, 110 input->code_descriptor_size }); 111 112 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_CONFIG_TYPE, 113 input->config_type); 114 115 if (input->config_type == kDiceConfigTypeInline) { 116 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_VALUE, 117 (UsefulBufC) { input->config_value, 118 sizeof(input->config_value) }); 119 } else { 120 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_CONFIG_DESCRIPTOR, 121 (UsefulBufC) { input->config_descriptor, 122 input->config_descriptor_size }); 123 } 124 125 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_HASH, 126 (UsefulBufC) { input->authority_hash, 127 sizeof(input->authority_hash) }); 128 129 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_AUTHORITY_DESCRIPTOR, 130 (UsefulBufC) { input->authority_descriptor, 131 input->authority_descriptor_size }); 132 133 QCBOREncode_AddInt64ToMapN(encode_ctx, DICE_MODE, input->mode); 134 135 QCBOREncode_AddBytesToMapN(encode_ctx, DICE_HIDDEN, 136 (UsefulBufC) { input->hidden, 137 sizeof(input->hidden) }); 138 139 QCBOREncode_CloseMap(encode_ctx); 140 QCBOREncode_CloseBstrWrap2(encode_ctx, true, NULL); 141 } 142 143 static QCBORError encode_derive_context(const struct derive_context_input_t *args, 144 UsefulBuf buf, 145 UsefulBufC *encoded_buf) 146 { 147 QCBOREncodeContext encode_ctx; 148 149 QCBOREncode_Init(&encode_ctx, buf); 150 151 QCBOREncode_OpenArray(&encode_ctx); 152 QCBOREncode_AddUInt64(&encode_ctx, DPE_DERIVE_CONTEXT); 153 154 /* Encode DeriveContext command */ 155 QCBOREncode_OpenMap(&encode_ctx); 156 QCBOREncode_AddBytesToMapN(&encode_ctx, 157 DPE_DERIVE_CONTEXT_CONTEXT_HANDLE, 158 (UsefulBufC) { &args->context_handle, 159 sizeof(args->context_handle) }); 160 QCBOREncode_AddUInt64ToMapN(&encode_ctx, 161 DPE_DERIVE_CONTEXT_CERT_ID, 162 args->cert_id); 163 QCBOREncode_AddBoolToMapN(&encode_ctx, 164 DPE_DERIVE_CONTEXT_RETAIN_PARENT_CONTEXT, 165 args->retain_parent_context); 166 QCBOREncode_AddBoolToMapN(&encode_ctx, 167 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_DERIVE, 168 args->allow_new_context_to_derive); 169 QCBOREncode_AddBoolToMapN(&encode_ctx, 170 DPE_DERIVE_CONTEXT_CREATE_CERTIFICATE, 171 args->create_certificate); 172 encode_dice_inputs(&encode_ctx, args->dice_inputs); 173 QCBOREncode_AddBytesToMapN(&encode_ctx, 174 DPE_DERIVE_CONTEXT_TARGET_LOCALITY, 175 (UsefulBufC) { &args->target_locality, 176 sizeof(args->target_locality) }); 177 QCBOREncode_AddBoolToMapN(&encode_ctx, 178 DPE_DERIVE_CONTEXT_RETURN_CERTIFICATE, 179 args->return_certificate); 180 QCBOREncode_AddBoolToMapN(&encode_ctx, 181 DPE_DERIVE_CONTEXT_ALLOW_NEW_CONTEXT_TO_EXPORT, 182 args->allow_new_context_to_export); 183 QCBOREncode_AddBoolToMapN(&encode_ctx, 184 DPE_DERIVE_CONTEXT_EXPORT_CDI, 185 args->export_cdi); 186 QCBOREncode_CloseMap(&encode_ctx); 187 188 QCBOREncode_CloseArray(&encode_ctx); 189 190 return QCBOREncode_Finish(&encode_ctx, encoded_buf); 191 } 192 193 static QCBORError decode_derive_context_response(UsefulBufC encoded_buf, 194 struct derive_context_output_t *args, 195 dpe_error_t *dpe_err) 196 { 197 QCBORDecodeContext decode_ctx; 198 UsefulBufC out; 199 int64_t response_dpe_err = 0; 200 201 QCBORDecode_Init(&decode_ctx, encoded_buf, QCBOR_DECODE_MODE_NORMAL); 202 203 QCBORDecode_EnterArray(&decode_ctx, NULL); 204 205 /* Get the error code from the response. DPE returns int32_t */ 206 QCBORDecode_GetInt64(&decode_ctx, &response_dpe_err); 207 *dpe_err = (dpe_error_t)response_dpe_err; 208 209 /* Decode DeriveContext response if successful */ 210 if (*dpe_err == DPE_NO_ERROR) { 211 QCBORDecode_EnterMap(&decode_ctx, NULL); 212 213 QCBORDecode_GetByteStringInMapN(&decode_ctx, 214 DPE_DERIVE_CONTEXT_NEW_CONTEXT_HANDLE, 215 &out); 216 if (out.len != sizeof(args->new_context_handle)) { 217 return QCBORDecode_Finish(&decode_ctx); 218 } 219 memcpy(&args->new_context_handle, out.ptr, out.len); 220 221 QCBORDecode_GetByteStringInMapN(&decode_ctx, 222 DPE_DERIVE_CONTEXT_PARENT_CONTEXT_HANDLE, 223 &out); 224 if (out.len != sizeof(args->new_parent_context_handle)) { 225 return QCBORDecode_Finish(&decode_ctx); 226 } 227 memcpy(&args->new_parent_context_handle, out.ptr, out.len); 228 229 QCBORDecode_GetByteStringInMapN(&decode_ctx, 230 DPE_DERIVE_CONTEXT_NEW_CERTIFICATE, 231 &out); 232 args->new_certificate = out.ptr; 233 args->new_certificate_size = out.len; 234 235 QCBORDecode_GetByteStringInMapN(&decode_ctx, 236 DPE_DERIVE_CONTEXT_EXPORTED_CDI, 237 &out); 238 args->exported_cdi = out.ptr; 239 args->exported_cdi_size = out.len; 240 241 QCBORDecode_ExitMap(&decode_ctx); 242 } 243 244 QCBORDecode_ExitArray(&decode_ctx); 245 246 return QCBORDecode_Finish(&decode_ctx); 247 } 248 249 static int32_t dpe_client_call(const char *cmd_input, size_t cmd_input_size, 250 char *cmd_output, size_t *cmd_output_size) 251 { 252 int32_t err; 253 254 psa_invec in_vec[] = { 255 { cmd_input, cmd_input_size }, 256 }; 257 psa_outvec out_vec[] = { 258 { cmd_output, *cmd_output_size }, 259 }; 260 261 err = psa_call(RSE_DPE_SERVICE_HANDLE, 0, 262 in_vec, IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec)); 263 264 if (err == PSA_SUCCESS) { 265 *cmd_output_size = out_vec[0].len; 266 } 267 268 return err; 269 } 270 271 dpe_error_t dpe_derive_context(int context_handle, 272 uint32_t cert_id, 273 bool retain_parent_context, 274 bool allow_new_context_to_derive, 275 bool create_certificate, 276 const DiceInputValues *dice_inputs, 277 int32_t target_locality, 278 bool return_certificate, 279 bool allow_new_context_to_export, 280 bool export_cdi, 281 int *new_context_handle, 282 int *new_parent_context_handle, 283 uint8_t *new_certificate_buf, 284 size_t new_certificate_buf_size, 285 size_t *new_certificate_actual_size, 286 uint8_t *exported_cdi_buf, 287 size_t exported_cdi_buf_size, 288 size_t *exported_cdi_actual_size) 289 { 290 int32_t service_err; 291 dpe_error_t dpe_err; 292 QCBORError qcbor_err; 293 UsefulBufC encoded_buf; 294 UsefulBuf_MAKE_STACK_UB(cmd_buf, 612); 295 296 const struct derive_context_input_t in_args = { 297 context_handle, 298 cert_id, 299 retain_parent_context, 300 allow_new_context_to_derive, 301 create_certificate, 302 dice_inputs, 303 target_locality, 304 return_certificate, 305 allow_new_context_to_export, 306 export_cdi, 307 }; 308 struct derive_context_output_t out_args; 309 310 /* 311 * Validate the output params here because they are not sent to the 312 * service. Input params are validated by the DPE service. 313 */ 314 if ((new_context_handle == NULL) || 315 (retain_parent_context == true && new_parent_context_handle == NULL) || 316 (return_certificate == true && 317 (new_certificate_buf == NULL || new_certificate_actual_size == NULL)) || 318 (export_cdi == true && 319 (exported_cdi_buf == NULL || exported_cdi_actual_size == NULL))) { 320 return DPE_INVALID_ARGUMENT; 321 } 322 323 qcbor_err = encode_derive_context(&in_args, cmd_buf, &encoded_buf); 324 if (qcbor_err != QCBOR_SUCCESS) { 325 return DPE_INTERNAL_ERROR; 326 } 327 328 service_err = dpe_client_call(encoded_buf.ptr, encoded_buf.len, 329 cmd_buf.ptr, &cmd_buf.len); 330 if (service_err != 0) { 331 return DPE_INTERNAL_ERROR; 332 } 333 334 qcbor_err = decode_derive_context_response(UsefulBuf_Const(cmd_buf), 335 &out_args, &dpe_err); 336 if (qcbor_err != QCBOR_SUCCESS) { 337 return DPE_INTERNAL_ERROR; 338 } else if (dpe_err != DPE_NO_ERROR) { 339 return dpe_err; 340 } 341 342 /* Copy returned values into caller's memory */ 343 *new_context_handle = out_args.new_context_handle; 344 345 if (retain_parent_context == true) { 346 *new_parent_context_handle = out_args.new_parent_context_handle; 347 } 348 349 if (return_certificate == true) { 350 if (out_args.new_certificate_size > new_certificate_buf_size) { 351 return DPE_INVALID_ARGUMENT; 352 } 353 354 memcpy(new_certificate_buf, out_args.new_certificate, 355 out_args.new_certificate_size); 356 *new_certificate_actual_size = out_args.new_certificate_size; 357 } 358 359 if (export_cdi == true) { 360 if (out_args.exported_cdi_size > exported_cdi_buf_size) { 361 return DPE_INVALID_ARGUMENT; 362 } 363 364 memcpy(exported_cdi_buf, out_args.exported_cdi, 365 out_args.exported_cdi_size); 366 *exported_cdi_actual_size = out_args.exported_cdi_size; 367 } 368 369 return DPE_NO_ERROR; 370 } 371