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