1bb154e3eSDorjoy Chowdhury /* 2bb154e3eSDorjoy Chowdhury * AWS Nitro Secure Module (NSM) device 3bb154e3eSDorjoy Chowdhury * 4bb154e3eSDorjoy Chowdhury * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com> 5bb154e3eSDorjoy Chowdhury * 6bb154e3eSDorjoy Chowdhury * This work is licensed under the terms of the GNU GPL, version 2 or 7bb154e3eSDorjoy Chowdhury * (at your option) any later version. See the COPYING file in the 8bb154e3eSDorjoy Chowdhury * top-level directory. 9bb154e3eSDorjoy Chowdhury */ 10bb154e3eSDorjoy Chowdhury 11bb154e3eSDorjoy Chowdhury #include "qemu/osdep.h" 12bb154e3eSDorjoy Chowdhury #include "qemu/iov.h" 13bb154e3eSDorjoy Chowdhury #include "qemu/guest-random.h" 14bb154e3eSDorjoy Chowdhury #include "qapi/error.h" 15bb154e3eSDorjoy Chowdhury 16bb154e3eSDorjoy Chowdhury #include "crypto/hash.h" 17bb154e3eSDorjoy Chowdhury #include "hw/virtio/virtio.h" 18bb154e3eSDorjoy Chowdhury #include "hw/virtio/virtio-nsm.h" 19bb154e3eSDorjoy Chowdhury #include "hw/virtio/cbor-helpers.h" 20bb154e3eSDorjoy Chowdhury #include "standard-headers/linux/virtio_ids.h" 21bb154e3eSDorjoy Chowdhury 22bb154e3eSDorjoy Chowdhury #define NSM_REQUEST_MAX_SIZE 0x1000 23bb154e3eSDorjoy Chowdhury #define NSM_RESPONSE_BUF_SIZE 0x3000 24bb154e3eSDorjoy Chowdhury #define NSM_RND_BUF_SIZE 256 25bb154e3eSDorjoy Chowdhury 26bb154e3eSDorjoy Chowdhury enum NSMResponseTypes { 27bb154e3eSDorjoy Chowdhury NSM_SUCCESS = 0, 28bb154e3eSDorjoy Chowdhury NSM_INVALID_ARGUMENT = 1, 29bb154e3eSDorjoy Chowdhury NSM_INVALID_INDEX = 2, 30bb154e3eSDorjoy Chowdhury NSM_READONLY_INDEX = 3, 31bb154e3eSDorjoy Chowdhury NSM_INVALID_OPERATION = 4, 32bb154e3eSDorjoy Chowdhury NSM_BUFFER_TOO_SMALL = 5, 33bb154e3eSDorjoy Chowdhury NSM_INPUT_TOO_LARGE = 6, 34bb154e3eSDorjoy Chowdhury NSM_INTERNAL_ERROR = 7, 35bb154e3eSDorjoy Chowdhury }; 36bb154e3eSDorjoy Chowdhury 37bb154e3eSDorjoy Chowdhury static const char *error_string(enum NSMResponseTypes type) 38bb154e3eSDorjoy Chowdhury { 39bb154e3eSDorjoy Chowdhury const char *str; 40bb154e3eSDorjoy Chowdhury switch (type) { 41bb154e3eSDorjoy Chowdhury case NSM_INVALID_ARGUMENT: 42bb154e3eSDorjoy Chowdhury str = "InvalidArgument"; 43bb154e3eSDorjoy Chowdhury break; 44bb154e3eSDorjoy Chowdhury case NSM_INVALID_INDEX: 45bb154e3eSDorjoy Chowdhury str = "InvalidIndex"; 46bb154e3eSDorjoy Chowdhury break; 47bb154e3eSDorjoy Chowdhury case NSM_READONLY_INDEX: 48bb154e3eSDorjoy Chowdhury str = "ReadOnlyIndex"; 49bb154e3eSDorjoy Chowdhury break; 50bb154e3eSDorjoy Chowdhury case NSM_INVALID_OPERATION: 51bb154e3eSDorjoy Chowdhury str = "InvalidOperation"; 52bb154e3eSDorjoy Chowdhury break; 53bb154e3eSDorjoy Chowdhury case NSM_BUFFER_TOO_SMALL: 54bb154e3eSDorjoy Chowdhury str = "BufferTooSmall"; 55bb154e3eSDorjoy Chowdhury break; 56bb154e3eSDorjoy Chowdhury case NSM_INPUT_TOO_LARGE: 57bb154e3eSDorjoy Chowdhury str = "InputTooLarge"; 58bb154e3eSDorjoy Chowdhury break; 59bb154e3eSDorjoy Chowdhury default: 60bb154e3eSDorjoy Chowdhury str = "InternalError"; 61bb154e3eSDorjoy Chowdhury break; 62bb154e3eSDorjoy Chowdhury } 63bb154e3eSDorjoy Chowdhury 64bb154e3eSDorjoy Chowdhury return str; 65bb154e3eSDorjoy Chowdhury } 66bb154e3eSDorjoy Chowdhury 67bb154e3eSDorjoy Chowdhury /* 68bb154e3eSDorjoy Chowdhury * Error response structure: 69bb154e3eSDorjoy Chowdhury * 70bb154e3eSDorjoy Chowdhury * { 71bb154e3eSDorjoy Chowdhury * Map(1) { 72bb154e3eSDorjoy Chowdhury * key = String("Error"), 73bb154e3eSDorjoy Chowdhury * value = String(error_name) 74bb154e3eSDorjoy Chowdhury * } 75bb154e3eSDorjoy Chowdhury * } 76bb154e3eSDorjoy Chowdhury * 77bb154e3eSDorjoy Chowdhury * where error_name can be one of the following: 78bb154e3eSDorjoy Chowdhury * InvalidArgument 79bb154e3eSDorjoy Chowdhury * InvalidIndex 80bb154e3eSDorjoy Chowdhury * InvalidResponse 81bb154e3eSDorjoy Chowdhury * ReadOnlyIndex 82bb154e3eSDorjoy Chowdhury * InvalidOperation 83bb154e3eSDorjoy Chowdhury * BufferTooSmall 84bb154e3eSDorjoy Chowdhury * InputTooLarge 85bb154e3eSDorjoy Chowdhury * InternalError 86bb154e3eSDorjoy Chowdhury */ 87bb154e3eSDorjoy Chowdhury 88bb154e3eSDorjoy Chowdhury static bool error_response(struct iovec *response, enum NSMResponseTypes error, 89bb154e3eSDorjoy Chowdhury Error **errp) 90bb154e3eSDorjoy Chowdhury { 91bb154e3eSDorjoy Chowdhury cbor_item_t *root; 92bb154e3eSDorjoy Chowdhury size_t len; 93bb154e3eSDorjoy Chowdhury bool r = false; 94bb154e3eSDorjoy Chowdhury 95bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 96bb154e3eSDorjoy Chowdhury if (!root) { 97bb154e3eSDorjoy Chowdhury goto err; 98bb154e3eSDorjoy Chowdhury } 99bb154e3eSDorjoy Chowdhury 100bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_string_to_map(root, "Error", error_string(error))) { 101bb154e3eSDorjoy Chowdhury goto err; 102bb154e3eSDorjoy Chowdhury } 103bb154e3eSDorjoy Chowdhury 104bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 105bb154e3eSDorjoy Chowdhury if (len == 0) { 106bb154e3eSDorjoy Chowdhury error_setg(errp, "Response buffer is small for %s response", 107bb154e3eSDorjoy Chowdhury error_string(error)); 108bb154e3eSDorjoy Chowdhury goto out; 109bb154e3eSDorjoy Chowdhury } 110bb154e3eSDorjoy Chowdhury response->iov_len = len; 111bb154e3eSDorjoy Chowdhury r = true; 112bb154e3eSDorjoy Chowdhury 113bb154e3eSDorjoy Chowdhury out: 114bb154e3eSDorjoy Chowdhury if (root) { 115bb154e3eSDorjoy Chowdhury cbor_decref(&root); 116bb154e3eSDorjoy Chowdhury } 117bb154e3eSDorjoy Chowdhury return r; 118bb154e3eSDorjoy Chowdhury 119bb154e3eSDorjoy Chowdhury err: 120bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize %s response", error_string(error)); 121bb154e3eSDorjoy Chowdhury goto out; 122bb154e3eSDorjoy Chowdhury } 123bb154e3eSDorjoy Chowdhury 124bb154e3eSDorjoy Chowdhury /* 125bb154e3eSDorjoy Chowdhury * GetRandom response structure: 126bb154e3eSDorjoy Chowdhury * 127bb154e3eSDorjoy Chowdhury * { 128bb154e3eSDorjoy Chowdhury * Map(1) { 129bb154e3eSDorjoy Chowdhury * key = String("GetRandom"), 130bb154e3eSDorjoy Chowdhury * value = Map(1) { 131bb154e3eSDorjoy Chowdhury * key = String("random"), 132bb154e3eSDorjoy Chowdhury * value = Byte_String() 133bb154e3eSDorjoy Chowdhury * } 134bb154e3eSDorjoy Chowdhury * } 135bb154e3eSDorjoy Chowdhury * } 136bb154e3eSDorjoy Chowdhury */ 137bb154e3eSDorjoy Chowdhury static bool handle_get_random(VirtIONSM *vnsm, struct iovec *request, 138bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 139bb154e3eSDorjoy Chowdhury { 140bb154e3eSDorjoy Chowdhury cbor_item_t *root, *nested_map; 141bb154e3eSDorjoy Chowdhury size_t len; 142bb154e3eSDorjoy Chowdhury uint8_t rnd[NSM_RND_BUF_SIZE]; 143bb154e3eSDorjoy Chowdhury bool r = false; 144bb154e3eSDorjoy Chowdhury 145bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 146bb154e3eSDorjoy Chowdhury if (!root) { 147bb154e3eSDorjoy Chowdhury goto err; 148bb154e3eSDorjoy Chowdhury } 149bb154e3eSDorjoy Chowdhury 150bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "GetRandom", 1, &nested_map)) { 151bb154e3eSDorjoy Chowdhury goto err; 152bb154e3eSDorjoy Chowdhury } 153bb154e3eSDorjoy Chowdhury 154bb154e3eSDorjoy Chowdhury qemu_guest_getrandom_nofail(rnd, NSM_RND_BUF_SIZE); 155bb154e3eSDorjoy Chowdhury 156bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bytestring_to_map(nested_map, "random", rnd, 157bb154e3eSDorjoy Chowdhury NSM_RND_BUF_SIZE)) { 158bb154e3eSDorjoy Chowdhury goto err; 159bb154e3eSDorjoy Chowdhury } 160bb154e3eSDorjoy Chowdhury 161bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 162bb154e3eSDorjoy Chowdhury if (len == 0) { 163bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) { 164bb154e3eSDorjoy Chowdhury r = true; 165bb154e3eSDorjoy Chowdhury } 166bb154e3eSDorjoy Chowdhury goto out; 167bb154e3eSDorjoy Chowdhury } 168bb154e3eSDorjoy Chowdhury 169bb154e3eSDorjoy Chowdhury response->iov_len = len; 170bb154e3eSDorjoy Chowdhury r = true; 171bb154e3eSDorjoy Chowdhury 172bb154e3eSDorjoy Chowdhury out: 173bb154e3eSDorjoy Chowdhury if (root) { 174bb154e3eSDorjoy Chowdhury cbor_decref(&root); 175bb154e3eSDorjoy Chowdhury } 176bb154e3eSDorjoy Chowdhury return r; 177bb154e3eSDorjoy Chowdhury 178bb154e3eSDorjoy Chowdhury err: 179bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize GetRandom response"); 180bb154e3eSDorjoy Chowdhury goto out; 181bb154e3eSDorjoy Chowdhury } 182bb154e3eSDorjoy Chowdhury 183bb154e3eSDorjoy Chowdhury /* 184bb154e3eSDorjoy Chowdhury * DescribeNSM response structure: 185bb154e3eSDorjoy Chowdhury * 186bb154e3eSDorjoy Chowdhury * { 187bb154e3eSDorjoy Chowdhury * Map(1) { 188bb154e3eSDorjoy Chowdhury * key = String("DescribeNSM"), 189bb154e3eSDorjoy Chowdhury * value = Map(7) { 190bb154e3eSDorjoy Chowdhury * key = String("digest"), 191bb154e3eSDorjoy Chowdhury * value = String("SHA384"), 192bb154e3eSDorjoy Chowdhury * key = String("max_pcrs"), 193bb154e3eSDorjoy Chowdhury * value = Uint8(32), 194bb154e3eSDorjoy Chowdhury * key = String("module_id"), 195bb154e3eSDorjoy Chowdhury * value = String("i-1234-enc5678"), 196bb154e3eSDorjoy Chowdhury * key = String("locked_pcrs"), 197bb154e3eSDorjoy Chowdhury * value = Array<Uint8>(), 198bb154e3eSDorjoy Chowdhury * key = String("version_major"), 199bb154e3eSDorjoy Chowdhury * value = Uint8(1), 200bb154e3eSDorjoy Chowdhury * key = String("version_minor"), 201bb154e3eSDorjoy Chowdhury * value = Uint8(0), 202bb154e3eSDorjoy Chowdhury * key = String("version_patch"), 203bb154e3eSDorjoy Chowdhury * value = Uint8(0) 204bb154e3eSDorjoy Chowdhury * } 205bb154e3eSDorjoy Chowdhury * } 206bb154e3eSDorjoy Chowdhury * } 207bb154e3eSDorjoy Chowdhury */ 208bb154e3eSDorjoy Chowdhury static bool handle_describe_nsm(VirtIONSM *vnsm, struct iovec *request, 209bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 210bb154e3eSDorjoy Chowdhury { 211bb154e3eSDorjoy Chowdhury cbor_item_t *root, *nested_map; 212bb154e3eSDorjoy Chowdhury uint16_t locked_pcrs_cnt = 0; 213bb154e3eSDorjoy Chowdhury uint8_t locked_pcrs_ind[NSM_MAX_PCRS]; 214bb154e3eSDorjoy Chowdhury size_t len; 215bb154e3eSDorjoy Chowdhury bool r = false; 216bb154e3eSDorjoy Chowdhury 217bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 218bb154e3eSDorjoy Chowdhury if (!root) { 219bb154e3eSDorjoy Chowdhury goto err; 220bb154e3eSDorjoy Chowdhury } 221bb154e3eSDorjoy Chowdhury 222bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "DescribeNSM", 7, &nested_map)) { 223bb154e3eSDorjoy Chowdhury goto err; 224bb154e3eSDorjoy Chowdhury } 225bb154e3eSDorjoy Chowdhury 226bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_string_to_map(nested_map, "digest", vnsm->digest)) { 227bb154e3eSDorjoy Chowdhury goto err; 228bb154e3eSDorjoy Chowdhury } 229bb154e3eSDorjoy Chowdhury 230bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_to_map(nested_map, "max_pcrs", vnsm->max_pcrs)) { 231bb154e3eSDorjoy Chowdhury goto err; 232bb154e3eSDorjoy Chowdhury } 233bb154e3eSDorjoy Chowdhury 234bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_string_to_map(nested_map, "module_id", 235bb154e3eSDorjoy Chowdhury vnsm->module_id)) { 236bb154e3eSDorjoy Chowdhury goto err; 237bb154e3eSDorjoy Chowdhury } 238bb154e3eSDorjoy Chowdhury 239bb154e3eSDorjoy Chowdhury for (uint8_t i = 0; i < NSM_MAX_PCRS; ++i) { 240bb154e3eSDorjoy Chowdhury if (vnsm->pcrs[i].locked) { 241bb154e3eSDorjoy Chowdhury locked_pcrs_ind[locked_pcrs_cnt++] = i; 242bb154e3eSDorjoy Chowdhury } 243bb154e3eSDorjoy Chowdhury } 244bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_array_to_map(nested_map, "locked_pcrs", 245bb154e3eSDorjoy Chowdhury locked_pcrs_ind, locked_pcrs_cnt)) { 246bb154e3eSDorjoy Chowdhury goto err; 247bb154e3eSDorjoy Chowdhury } 248bb154e3eSDorjoy Chowdhury 249bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_to_map(nested_map, "version_major", 250bb154e3eSDorjoy Chowdhury vnsm->version_major)) { 251bb154e3eSDorjoy Chowdhury goto err; 252bb154e3eSDorjoy Chowdhury } 253bb154e3eSDorjoy Chowdhury 254bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_to_map(nested_map, "version_minor", 255bb154e3eSDorjoy Chowdhury vnsm->version_minor)) { 256bb154e3eSDorjoy Chowdhury goto err; 257bb154e3eSDorjoy Chowdhury } 258bb154e3eSDorjoy Chowdhury 259bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_to_map(nested_map, "version_patch", 260bb154e3eSDorjoy Chowdhury vnsm->version_patch)) { 261bb154e3eSDorjoy Chowdhury goto err; 262bb154e3eSDorjoy Chowdhury } 263bb154e3eSDorjoy Chowdhury 264bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 265bb154e3eSDorjoy Chowdhury if (len == 0) { 266bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) { 267bb154e3eSDorjoy Chowdhury r = true; 268bb154e3eSDorjoy Chowdhury } 269bb154e3eSDorjoy Chowdhury goto out; 270bb154e3eSDorjoy Chowdhury } 271bb154e3eSDorjoy Chowdhury 272bb154e3eSDorjoy Chowdhury response->iov_len = len; 273bb154e3eSDorjoy Chowdhury r = true; 274bb154e3eSDorjoy Chowdhury 275bb154e3eSDorjoy Chowdhury out: 276bb154e3eSDorjoy Chowdhury if (root) { 277bb154e3eSDorjoy Chowdhury cbor_decref(&root); 278bb154e3eSDorjoy Chowdhury } 279bb154e3eSDorjoy Chowdhury return r; 280bb154e3eSDorjoy Chowdhury 281bb154e3eSDorjoy Chowdhury err: 282bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize DescribeNSM response"); 283bb154e3eSDorjoy Chowdhury goto out; 284bb154e3eSDorjoy Chowdhury } 285bb154e3eSDorjoy Chowdhury 286bb154e3eSDorjoy Chowdhury /* 287bb154e3eSDorjoy Chowdhury * DescribePCR request structure: 288bb154e3eSDorjoy Chowdhury * 289bb154e3eSDorjoy Chowdhury * { 290bb154e3eSDorjoy Chowdhury * Map(1) { 291bb154e3eSDorjoy Chowdhury * key = String("DescribePCR"), 292bb154e3eSDorjoy Chowdhury * value = Map(1) { 293bb154e3eSDorjoy Chowdhury * key = String("index"), 294bb154e3eSDorjoy Chowdhury * value = Uint8(pcr) 295bb154e3eSDorjoy Chowdhury * } 296bb154e3eSDorjoy Chowdhury * } 297bb154e3eSDorjoy Chowdhury * } 298bb154e3eSDorjoy Chowdhury */ 299bb154e3eSDorjoy Chowdhury typedef struct NSMDescribePCRReq { 300bb154e3eSDorjoy Chowdhury uint8_t index; 301bb154e3eSDorjoy Chowdhury } NSMDescribePCRReq; 302bb154e3eSDorjoy Chowdhury 303bb154e3eSDorjoy Chowdhury static enum NSMResponseTypes get_nsm_describe_pcr_req( 304bb154e3eSDorjoy Chowdhury uint8_t *req, size_t len, 305bb154e3eSDorjoy Chowdhury NSMDescribePCRReq *nsm_req) 306bb154e3eSDorjoy Chowdhury { 307bb154e3eSDorjoy Chowdhury size_t size; 308bb154e3eSDorjoy Chowdhury uint8_t *str; 309bb154e3eSDorjoy Chowdhury struct cbor_pair *pair; 310bb154e3eSDorjoy Chowdhury cbor_item_t *item = NULL; 311bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 312bb154e3eSDorjoy Chowdhury enum NSMResponseTypes r = NSM_INVALID_OPERATION; 313bb154e3eSDorjoy Chowdhury 314bb154e3eSDorjoy Chowdhury item = cbor_load(req, len, &result); 315bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 316bb154e3eSDorjoy Chowdhury goto cleanup; 317bb154e3eSDorjoy Chowdhury } 318bb154e3eSDorjoy Chowdhury 319bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(item); 320bb154e3eSDorjoy Chowdhury if (!cbor_isa_map(pair->value)) { 321bb154e3eSDorjoy Chowdhury goto cleanup; 322bb154e3eSDorjoy Chowdhury } 323bb154e3eSDorjoy Chowdhury size = cbor_map_size(pair->value); 324bb154e3eSDorjoy Chowdhury if (size < 1) { 325bb154e3eSDorjoy Chowdhury goto cleanup; 326bb154e3eSDorjoy Chowdhury } 327bb154e3eSDorjoy Chowdhury 328bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(pair->value); 329bb154e3eSDorjoy Chowdhury for (int i = 0; i < size; ++i) { 330bb154e3eSDorjoy Chowdhury if (!cbor_isa_string(pair[i].key)) { 331bb154e3eSDorjoy Chowdhury continue; 332bb154e3eSDorjoy Chowdhury } 333bb154e3eSDorjoy Chowdhury 334bb154e3eSDorjoy Chowdhury str = cbor_string_handle(pair[i].key); 335bb154e3eSDorjoy Chowdhury if (str && cbor_string_length(pair[i].key) == 5 && 336bb154e3eSDorjoy Chowdhury memcmp(str, "index", 5) == 0) { 337bb154e3eSDorjoy Chowdhury if (!cbor_isa_uint(pair[i].value) || 338bb154e3eSDorjoy Chowdhury cbor_int_get_width(pair[i].value) != CBOR_INT_8) { 339bb154e3eSDorjoy Chowdhury break; 340bb154e3eSDorjoy Chowdhury } 341bb154e3eSDorjoy Chowdhury 342bb154e3eSDorjoy Chowdhury nsm_req->index = cbor_get_uint8(pair[i].value); 343bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 344bb154e3eSDorjoy Chowdhury break; 345bb154e3eSDorjoy Chowdhury } 346bb154e3eSDorjoy Chowdhury } 347bb154e3eSDorjoy Chowdhury 348bb154e3eSDorjoy Chowdhury cleanup: 349bb154e3eSDorjoy Chowdhury if (item) { 350bb154e3eSDorjoy Chowdhury cbor_decref(&item); 351bb154e3eSDorjoy Chowdhury } 352bb154e3eSDorjoy Chowdhury return r; 353bb154e3eSDorjoy Chowdhury } 354bb154e3eSDorjoy Chowdhury 355bb154e3eSDorjoy Chowdhury /* 356bb154e3eSDorjoy Chowdhury * DescribePCR response structure: 357bb154e3eSDorjoy Chowdhury * 358bb154e3eSDorjoy Chowdhury * { 359bb154e3eSDorjoy Chowdhury * Map(1) { 360bb154e3eSDorjoy Chowdhury * key = String("DescribePCR"), 361bb154e3eSDorjoy Chowdhury * value = Map(2) { 362bb154e3eSDorjoy Chowdhury * key = String("data"), 363bb154e3eSDorjoy Chowdhury * value = Byte_String(), 364bb154e3eSDorjoy Chowdhury * key = String("lock"), 365bb154e3eSDorjoy Chowdhury * value = Bool() 366bb154e3eSDorjoy Chowdhury * } 367bb154e3eSDorjoy Chowdhury * } 368bb154e3eSDorjoy Chowdhury * } 369bb154e3eSDorjoy Chowdhury */ 370bb154e3eSDorjoy Chowdhury static bool handle_describe_pcr(VirtIONSM *vnsm, struct iovec *request, 371bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 372bb154e3eSDorjoy Chowdhury { 373bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 374bb154e3eSDorjoy Chowdhury cbor_item_t *nested_map; 375bb154e3eSDorjoy Chowdhury size_t len; 376bb154e3eSDorjoy Chowdhury NSMDescribePCRReq nsm_req; 377bb154e3eSDorjoy Chowdhury enum NSMResponseTypes type; 378bb154e3eSDorjoy Chowdhury struct PCRInfo *pcr; 379bb154e3eSDorjoy Chowdhury bool r = false; 380bb154e3eSDorjoy Chowdhury 381bb154e3eSDorjoy Chowdhury type = get_nsm_describe_pcr_req(request->iov_base, request->iov_len, 382bb154e3eSDorjoy Chowdhury &nsm_req); 383bb154e3eSDorjoy Chowdhury if (type != NSM_SUCCESS) { 384bb154e3eSDorjoy Chowdhury if (error_response(response, type, errp)) { 385bb154e3eSDorjoy Chowdhury r = true; 386bb154e3eSDorjoy Chowdhury } 387bb154e3eSDorjoy Chowdhury goto out; 388bb154e3eSDorjoy Chowdhury } 389bb154e3eSDorjoy Chowdhury if (nsm_req.index >= vnsm->max_pcrs) { 390bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INVALID_INDEX, errp)) { 391bb154e3eSDorjoy Chowdhury r = true; 392bb154e3eSDorjoy Chowdhury } 393bb154e3eSDorjoy Chowdhury goto out; 394bb154e3eSDorjoy Chowdhury } 395bb154e3eSDorjoy Chowdhury pcr = &(vnsm->pcrs[nsm_req.index]); 396bb154e3eSDorjoy Chowdhury 397bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 398bb154e3eSDorjoy Chowdhury if (!root) { 399bb154e3eSDorjoy Chowdhury goto err; 400bb154e3eSDorjoy Chowdhury } 401bb154e3eSDorjoy Chowdhury 402bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "DescribePCR", 2, &nested_map)) { 403bb154e3eSDorjoy Chowdhury goto err; 404bb154e3eSDorjoy Chowdhury } 405bb154e3eSDorjoy Chowdhury 406bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bytestring_to_map(nested_map, "data", pcr->data, 407bb154e3eSDorjoy Chowdhury QCRYPTO_HASH_DIGEST_LEN_SHA384)) { 408bb154e3eSDorjoy Chowdhury goto err; 409bb154e3eSDorjoy Chowdhury } 410bb154e3eSDorjoy Chowdhury 411bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bool_to_map(nested_map, "lock", pcr->locked)) { 412bb154e3eSDorjoy Chowdhury goto err; 413bb154e3eSDorjoy Chowdhury } 414bb154e3eSDorjoy Chowdhury 415bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 416bb154e3eSDorjoy Chowdhury if (len == 0) { 417bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) { 418bb154e3eSDorjoy Chowdhury r = true; 419bb154e3eSDorjoy Chowdhury } 420bb154e3eSDorjoy Chowdhury goto out; 421bb154e3eSDorjoy Chowdhury } 422bb154e3eSDorjoy Chowdhury 423bb154e3eSDorjoy Chowdhury response->iov_len = len; 424bb154e3eSDorjoy Chowdhury r = true; 425bb154e3eSDorjoy Chowdhury 426bb154e3eSDorjoy Chowdhury out: 427bb154e3eSDorjoy Chowdhury if (root) { 428bb154e3eSDorjoy Chowdhury cbor_decref(&root); 429bb154e3eSDorjoy Chowdhury } 430bb154e3eSDorjoy Chowdhury return r; 431bb154e3eSDorjoy Chowdhury 432bb154e3eSDorjoy Chowdhury err: 433bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize DescribePCR response"); 434bb154e3eSDorjoy Chowdhury goto out; 435bb154e3eSDorjoy Chowdhury } 436bb154e3eSDorjoy Chowdhury 437bb154e3eSDorjoy Chowdhury /* 438bb154e3eSDorjoy Chowdhury * ExtendPCR request structure: 439bb154e3eSDorjoy Chowdhury * 440bb154e3eSDorjoy Chowdhury * { 441bb154e3eSDorjoy Chowdhury * Map(1) { 442bb154e3eSDorjoy Chowdhury * key = String("ExtendPCR"), 443bb154e3eSDorjoy Chowdhury * value = Map(2) { 444bb154e3eSDorjoy Chowdhury * key = String("index"), 445bb154e3eSDorjoy Chowdhury * value = Uint8(pcr), 446bb154e3eSDorjoy Chowdhury * key = String("data"), 447d4ee9a11SDorjoy Chowdhury * value = Byte_String(data) || String(data), 448bb154e3eSDorjoy Chowdhury * } 449bb154e3eSDorjoy Chowdhury * } 450bb154e3eSDorjoy Chowdhury * } 451bb154e3eSDorjoy Chowdhury */ 452bb154e3eSDorjoy Chowdhury typedef struct NSMExtendPCRReq { 453bb154e3eSDorjoy Chowdhury uint8_t index; 454bb154e3eSDorjoy Chowdhury uint16_t data_len; 455bb154e3eSDorjoy Chowdhury uint8_t data[NSM_REQUEST_MAX_SIZE]; 456bb154e3eSDorjoy Chowdhury } NSMExtendPCRReq; 457bb154e3eSDorjoy Chowdhury 458bb154e3eSDorjoy Chowdhury static enum NSMResponseTypes get_nsm_extend_pcr_req(uint8_t *req, size_t len, 459bb154e3eSDorjoy Chowdhury NSMExtendPCRReq *nsm_req) 460bb154e3eSDorjoy Chowdhury { 461bb154e3eSDorjoy Chowdhury cbor_item_t *item = NULL; 462bb154e3eSDorjoy Chowdhury size_t size ; 463bb154e3eSDorjoy Chowdhury uint8_t *str; 464bb154e3eSDorjoy Chowdhury bool index_found = false; 465bb154e3eSDorjoy Chowdhury bool data_found = false; 466bb154e3eSDorjoy Chowdhury struct cbor_pair *pair; 467bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 468bb154e3eSDorjoy Chowdhury enum NSMResponseTypes r = NSM_INVALID_OPERATION; 469bb154e3eSDorjoy Chowdhury 470bb154e3eSDorjoy Chowdhury item = cbor_load(req, len, &result); 471bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 472bb154e3eSDorjoy Chowdhury goto cleanup; 473bb154e3eSDorjoy Chowdhury } 474bb154e3eSDorjoy Chowdhury 475bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(item); 476bb154e3eSDorjoy Chowdhury if (!cbor_isa_map(pair->value)) { 477bb154e3eSDorjoy Chowdhury goto cleanup; 478bb154e3eSDorjoy Chowdhury } 479bb154e3eSDorjoy Chowdhury size = cbor_map_size(pair->value); 480bb154e3eSDorjoy Chowdhury if (size < 2) { 481bb154e3eSDorjoy Chowdhury goto cleanup; 482bb154e3eSDorjoy Chowdhury } 483bb154e3eSDorjoy Chowdhury 484bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(pair->value); 485bb154e3eSDorjoy Chowdhury for (int i = 0; i < size; ++i) { 486bb154e3eSDorjoy Chowdhury if (!cbor_isa_string(pair[i].key)) { 487bb154e3eSDorjoy Chowdhury continue; 488bb154e3eSDorjoy Chowdhury } 489bb154e3eSDorjoy Chowdhury str = cbor_string_handle(pair[i].key); 490bb154e3eSDorjoy Chowdhury if (!str) { 491bb154e3eSDorjoy Chowdhury continue; 492bb154e3eSDorjoy Chowdhury } 493bb154e3eSDorjoy Chowdhury 494bb154e3eSDorjoy Chowdhury if (cbor_string_length(pair[i].key) == 5 && 495bb154e3eSDorjoy Chowdhury memcmp(str, "index", 5) == 0) { 496bb154e3eSDorjoy Chowdhury if (!cbor_isa_uint(pair[i].value) || 497bb154e3eSDorjoy Chowdhury cbor_int_get_width(pair[i].value) != CBOR_INT_8) { 498bb154e3eSDorjoy Chowdhury goto cleanup; 499bb154e3eSDorjoy Chowdhury } 500bb154e3eSDorjoy Chowdhury nsm_req->index = cbor_get_uint8(pair[i].value); 501bb154e3eSDorjoy Chowdhury index_found = true; 502bb154e3eSDorjoy Chowdhury continue; 503bb154e3eSDorjoy Chowdhury } 504bb154e3eSDorjoy Chowdhury 505bb154e3eSDorjoy Chowdhury if (cbor_string_length(pair[i].key) == 4 && 506bb154e3eSDorjoy Chowdhury memcmp(str, "data", 4) == 0) { 507d4ee9a11SDorjoy Chowdhury if (cbor_isa_bytestring(pair[i].value)) { 508bb154e3eSDorjoy Chowdhury str = cbor_bytestring_handle(pair[i].value); 509bb154e3eSDorjoy Chowdhury if (!str) { 510bb154e3eSDorjoy Chowdhury goto cleanup; 511bb154e3eSDorjoy Chowdhury } 512bb154e3eSDorjoy Chowdhury nsm_req->data_len = cbor_bytestring_length(pair[i].value); 513d4ee9a11SDorjoy Chowdhury } else if (cbor_isa_string(pair[i].value)) { 514d4ee9a11SDorjoy Chowdhury str = cbor_string_handle(pair[i].value); 515d4ee9a11SDorjoy Chowdhury if (!str) { 516d4ee9a11SDorjoy Chowdhury goto cleanup; 517d4ee9a11SDorjoy Chowdhury } 518d4ee9a11SDorjoy Chowdhury nsm_req->data_len = cbor_string_length(pair[i].value); 519d4ee9a11SDorjoy Chowdhury } else { 520d4ee9a11SDorjoy Chowdhury goto cleanup; 521d4ee9a11SDorjoy Chowdhury } 522bb154e3eSDorjoy Chowdhury /* 523bb154e3eSDorjoy Chowdhury * nsm_req->data_len will be smaller than NSM_REQUEST_MAX_SIZE as 524bb154e3eSDorjoy Chowdhury * we already check for the max request size before processing 525bb154e3eSDorjoy Chowdhury * any request. So it's safe to copy. 526bb154e3eSDorjoy Chowdhury */ 527bb154e3eSDorjoy Chowdhury memcpy(nsm_req->data, str, nsm_req->data_len); 528bb154e3eSDorjoy Chowdhury data_found = true; 529bb154e3eSDorjoy Chowdhury continue; 530bb154e3eSDorjoy Chowdhury } 531bb154e3eSDorjoy Chowdhury } 532bb154e3eSDorjoy Chowdhury 533bb154e3eSDorjoy Chowdhury if (index_found && data_found) { 534bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 535bb154e3eSDorjoy Chowdhury } 536bb154e3eSDorjoy Chowdhury 537bb154e3eSDorjoy Chowdhury cleanup: 538bb154e3eSDorjoy Chowdhury if (item) { 539bb154e3eSDorjoy Chowdhury cbor_decref(&item); 540bb154e3eSDorjoy Chowdhury } 541bb154e3eSDorjoy Chowdhury return r; 542bb154e3eSDorjoy Chowdhury } 543bb154e3eSDorjoy Chowdhury 544bb154e3eSDorjoy Chowdhury /* 545bb154e3eSDorjoy Chowdhury * ExtendPCR response structure: 546bb154e3eSDorjoy Chowdhury * 547bb154e3eSDorjoy Chowdhury * { 548bb154e3eSDorjoy Chowdhury * Map(1) { 549bb154e3eSDorjoy Chowdhury * key = String("ExtendPCR"), 550bb154e3eSDorjoy Chowdhury * value = Map(1) { 551bb154e3eSDorjoy Chowdhury * key = String("data"), 552bb154e3eSDorjoy Chowdhury * value = Byte_String() 553bb154e3eSDorjoy Chowdhury * } 554bb154e3eSDorjoy Chowdhury * } 555bb154e3eSDorjoy Chowdhury * } 556bb154e3eSDorjoy Chowdhury */ 557bb154e3eSDorjoy Chowdhury static bool handle_extend_pcr(VirtIONSM *vnsm, struct iovec *request, 558bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 559bb154e3eSDorjoy Chowdhury { 560bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 561bb154e3eSDorjoy Chowdhury cbor_item_t *nested_map; 562bb154e3eSDorjoy Chowdhury size_t len; 563bb154e3eSDorjoy Chowdhury struct PCRInfo *pcr; 564bb154e3eSDorjoy Chowdhury enum NSMResponseTypes type; 565bb154e3eSDorjoy Chowdhury bool r = false; 566bb154e3eSDorjoy Chowdhury g_autofree NSMExtendPCRReq *nsm_req = g_malloc(sizeof(NSMExtendPCRReq)); 567bb154e3eSDorjoy Chowdhury 568bb154e3eSDorjoy Chowdhury type = get_nsm_extend_pcr_req(request->iov_base, request->iov_len, 569bb154e3eSDorjoy Chowdhury nsm_req); 570bb154e3eSDorjoy Chowdhury if (type != NSM_SUCCESS) { 571bb154e3eSDorjoy Chowdhury if (error_response(response, type, errp)) { 572bb154e3eSDorjoy Chowdhury r = true; 573bb154e3eSDorjoy Chowdhury } 574bb154e3eSDorjoy Chowdhury goto out; 575bb154e3eSDorjoy Chowdhury } 576bb154e3eSDorjoy Chowdhury if (nsm_req->index >= vnsm->max_pcrs) { 577bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INVALID_INDEX, errp)) { 578bb154e3eSDorjoy Chowdhury r = true; 579bb154e3eSDorjoy Chowdhury } 580bb154e3eSDorjoy Chowdhury goto out; 581bb154e3eSDorjoy Chowdhury } 582bb154e3eSDorjoy Chowdhury 583bb154e3eSDorjoy Chowdhury pcr = &(vnsm->pcrs[nsm_req->index]); 584bb154e3eSDorjoy Chowdhury 585bb154e3eSDorjoy Chowdhury if (pcr->locked) { 586bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_READONLY_INDEX, errp)) { 587bb154e3eSDorjoy Chowdhury r = true; 588bb154e3eSDorjoy Chowdhury } 589bb154e3eSDorjoy Chowdhury goto out; 590bb154e3eSDorjoy Chowdhury } 591bb154e3eSDorjoy Chowdhury 592bb154e3eSDorjoy Chowdhury if (!vnsm->extend_pcr(vnsm, nsm_req->index, nsm_req->data, 593bb154e3eSDorjoy Chowdhury nsm_req->data_len)) { 594bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INTERNAL_ERROR, errp)) { 595bb154e3eSDorjoy Chowdhury r = true; 596bb154e3eSDorjoy Chowdhury } 597bb154e3eSDorjoy Chowdhury goto out; 598bb154e3eSDorjoy Chowdhury } 599bb154e3eSDorjoy Chowdhury 600bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 601bb154e3eSDorjoy Chowdhury if (!root) { 602bb154e3eSDorjoy Chowdhury goto err; 603bb154e3eSDorjoy Chowdhury } 604bb154e3eSDorjoy Chowdhury 605bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "ExtendPCR", 1, &nested_map)) { 606bb154e3eSDorjoy Chowdhury goto err; 607bb154e3eSDorjoy Chowdhury } 608bb154e3eSDorjoy Chowdhury 609bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bytestring_to_map(nested_map, "data", pcr->data, 610bb154e3eSDorjoy Chowdhury QCRYPTO_HASH_DIGEST_LEN_SHA384)) { 611bb154e3eSDorjoy Chowdhury goto err; 612bb154e3eSDorjoy Chowdhury } 613bb154e3eSDorjoy Chowdhury 614bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 615bb154e3eSDorjoy Chowdhury if (len == 0) { 616bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) { 617bb154e3eSDorjoy Chowdhury r = true; 618bb154e3eSDorjoy Chowdhury } 619bb154e3eSDorjoy Chowdhury goto out; 620bb154e3eSDorjoy Chowdhury } 621bb154e3eSDorjoy Chowdhury 622bb154e3eSDorjoy Chowdhury response->iov_len = len; 623bb154e3eSDorjoy Chowdhury r = true; 624bb154e3eSDorjoy Chowdhury 625bb154e3eSDorjoy Chowdhury out: 626bb154e3eSDorjoy Chowdhury if (root) { 627bb154e3eSDorjoy Chowdhury cbor_decref(&root); 628bb154e3eSDorjoy Chowdhury } 629bb154e3eSDorjoy Chowdhury return r; 630bb154e3eSDorjoy Chowdhury 631bb154e3eSDorjoy Chowdhury err: 632bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize DescribePCR response"); 633bb154e3eSDorjoy Chowdhury goto out; 634bb154e3eSDorjoy Chowdhury } 635bb154e3eSDorjoy Chowdhury 636bb154e3eSDorjoy Chowdhury /* 637bb154e3eSDorjoy Chowdhury * LockPCR request structure: 638bb154e3eSDorjoy Chowdhury * 639bb154e3eSDorjoy Chowdhury * { 640bb154e3eSDorjoy Chowdhury * Map(1) { 641bb154e3eSDorjoy Chowdhury * key = String("LockPCR"), 642bb154e3eSDorjoy Chowdhury * value = Map(1) { 643bb154e3eSDorjoy Chowdhury * key = String("index"), 644bb154e3eSDorjoy Chowdhury * value = Uint8(pcr) 645bb154e3eSDorjoy Chowdhury * } 646bb154e3eSDorjoy Chowdhury * } 647bb154e3eSDorjoy Chowdhury * } 648bb154e3eSDorjoy Chowdhury */ 649bb154e3eSDorjoy Chowdhury typedef struct NSMLockPCRReq { 650bb154e3eSDorjoy Chowdhury uint8_t index; 651bb154e3eSDorjoy Chowdhury } NSMLockPCRReq; 652bb154e3eSDorjoy Chowdhury 653bb154e3eSDorjoy Chowdhury static enum NSMResponseTypes get_nsm_lock_pcr_req(uint8_t *req, size_t len, 654bb154e3eSDorjoy Chowdhury NSMLockPCRReq *nsm_req) 655bb154e3eSDorjoy Chowdhury { 656bb154e3eSDorjoy Chowdhury cbor_item_t *item = NULL; 657bb154e3eSDorjoy Chowdhury size_t size; 658bb154e3eSDorjoy Chowdhury uint8_t *str; 659bb154e3eSDorjoy Chowdhury struct cbor_pair *pair; 660bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 661bb154e3eSDorjoy Chowdhury enum NSMResponseTypes r = NSM_INVALID_OPERATION; 662bb154e3eSDorjoy Chowdhury 663bb154e3eSDorjoy Chowdhury item = cbor_load(req, len, &result); 664bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 665bb154e3eSDorjoy Chowdhury goto cleanup; 666bb154e3eSDorjoy Chowdhury } 667bb154e3eSDorjoy Chowdhury 668bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(item); 669bb154e3eSDorjoy Chowdhury if (!cbor_isa_map(pair->value)) { 670bb154e3eSDorjoy Chowdhury goto cleanup; 671bb154e3eSDorjoy Chowdhury } 672bb154e3eSDorjoy Chowdhury size = cbor_map_size(pair->value); 673bb154e3eSDorjoy Chowdhury if (size < 1) { 674bb154e3eSDorjoy Chowdhury goto cleanup; 675bb154e3eSDorjoy Chowdhury } 676bb154e3eSDorjoy Chowdhury 677bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(pair->value); 678bb154e3eSDorjoy Chowdhury for (int i = 0; i < size; ++i) { 679bb154e3eSDorjoy Chowdhury if (!cbor_isa_string(pair[i].key)) { 680bb154e3eSDorjoy Chowdhury continue; 681bb154e3eSDorjoy Chowdhury } 682bb154e3eSDorjoy Chowdhury str = cbor_string_handle(pair[i].key); 683bb154e3eSDorjoy Chowdhury if (str && cbor_string_length(pair[i].key) == 5 && 684bb154e3eSDorjoy Chowdhury memcmp(str, "index", 5) == 0) { 685bb154e3eSDorjoy Chowdhury if (!cbor_isa_uint(pair[i].value) || 686bb154e3eSDorjoy Chowdhury cbor_int_get_width(pair[i].value) != CBOR_INT_8) { 687bb154e3eSDorjoy Chowdhury break; 688bb154e3eSDorjoy Chowdhury } 689bb154e3eSDorjoy Chowdhury 690bb154e3eSDorjoy Chowdhury nsm_req->index = cbor_get_uint8(pair[i].value); 691bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 692bb154e3eSDorjoy Chowdhury break; 693bb154e3eSDorjoy Chowdhury } 694bb154e3eSDorjoy Chowdhury } 695bb154e3eSDorjoy Chowdhury 696bb154e3eSDorjoy Chowdhury cleanup: 697bb154e3eSDorjoy Chowdhury if (item) { 698bb154e3eSDorjoy Chowdhury cbor_decref(&item); 699bb154e3eSDorjoy Chowdhury } 700bb154e3eSDorjoy Chowdhury return r; 701bb154e3eSDorjoy Chowdhury } 702bb154e3eSDorjoy Chowdhury 703bb154e3eSDorjoy Chowdhury /* 704bb154e3eSDorjoy Chowdhury * LockPCR success response structure: 705bb154e3eSDorjoy Chowdhury * { 706bb154e3eSDorjoy Chowdhury * String("LockPCR") 707bb154e3eSDorjoy Chowdhury * } 708bb154e3eSDorjoy Chowdhury */ 709bb154e3eSDorjoy Chowdhury static bool handle_lock_pcr(VirtIONSM *vnsm, struct iovec *request, 710bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 711bb154e3eSDorjoy Chowdhury { 712bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 713bb154e3eSDorjoy Chowdhury size_t len; 714bb154e3eSDorjoy Chowdhury NSMLockPCRReq nsm_req; 715bb154e3eSDorjoy Chowdhury enum NSMResponseTypes type; 716bb154e3eSDorjoy Chowdhury struct PCRInfo *pcr; 717bb154e3eSDorjoy Chowdhury bool r = false; 718bb154e3eSDorjoy Chowdhury 719bb154e3eSDorjoy Chowdhury type = get_nsm_lock_pcr_req(request->iov_base, request->iov_len, &nsm_req); 720bb154e3eSDorjoy Chowdhury if (type != NSM_SUCCESS) { 721bb154e3eSDorjoy Chowdhury if (error_response(response, type, errp)) { 722bb154e3eSDorjoy Chowdhury r = true; 723bb154e3eSDorjoy Chowdhury } 724bb154e3eSDorjoy Chowdhury goto cleanup; 725bb154e3eSDorjoy Chowdhury } 726bb154e3eSDorjoy Chowdhury if (nsm_req.index >= vnsm->max_pcrs) { 727bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INVALID_INDEX, errp)) { 728bb154e3eSDorjoy Chowdhury r = true; 729bb154e3eSDorjoy Chowdhury } 730bb154e3eSDorjoy Chowdhury goto cleanup; 731bb154e3eSDorjoy Chowdhury } 732bb154e3eSDorjoy Chowdhury 733bb154e3eSDorjoy Chowdhury pcr = &(vnsm->pcrs[nsm_req.index]); 734bb154e3eSDorjoy Chowdhury 735bb154e3eSDorjoy Chowdhury if (pcr->locked) { 736bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_READONLY_INDEX, errp)) { 737bb154e3eSDorjoy Chowdhury r = true; 738bb154e3eSDorjoy Chowdhury } 739bb154e3eSDorjoy Chowdhury goto cleanup; 740bb154e3eSDorjoy Chowdhury } 741bb154e3eSDorjoy Chowdhury 742bb154e3eSDorjoy Chowdhury pcr->locked = true; 743bb154e3eSDorjoy Chowdhury 744bb154e3eSDorjoy Chowdhury root = cbor_build_string("LockPCR"); 745bb154e3eSDorjoy Chowdhury if (!root) { 746bb154e3eSDorjoy Chowdhury goto err; 747bb154e3eSDorjoy Chowdhury } 748bb154e3eSDorjoy Chowdhury 749bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 750bb154e3eSDorjoy Chowdhury if (len == 0) { 751bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) { 752bb154e3eSDorjoy Chowdhury r = true; 753bb154e3eSDorjoy Chowdhury } 754bb154e3eSDorjoy Chowdhury goto cleanup; 755bb154e3eSDorjoy Chowdhury } 756bb154e3eSDorjoy Chowdhury 757bb154e3eSDorjoy Chowdhury response->iov_len = len; 758bb154e3eSDorjoy Chowdhury r = true; 759bb154e3eSDorjoy Chowdhury goto cleanup; 760bb154e3eSDorjoy Chowdhury 761bb154e3eSDorjoy Chowdhury err: 762bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize LockPCR response"); 763bb154e3eSDorjoy Chowdhury 764bb154e3eSDorjoy Chowdhury cleanup: 765bb154e3eSDorjoy Chowdhury if (root) { 766bb154e3eSDorjoy Chowdhury cbor_decref(&root); 767bb154e3eSDorjoy Chowdhury } 768bb154e3eSDorjoy Chowdhury return r; 769bb154e3eSDorjoy Chowdhury } 770bb154e3eSDorjoy Chowdhury 771bb154e3eSDorjoy Chowdhury /* 772bb154e3eSDorjoy Chowdhury * LockPCRs request structure: 773bb154e3eSDorjoy Chowdhury * 774bb154e3eSDorjoy Chowdhury * { 775bb154e3eSDorjoy Chowdhury * Map(1) { 776bb154e3eSDorjoy Chowdhury * key = String("LockPCRs"), 777bb154e3eSDorjoy Chowdhury * value = Map(1) { 778bb154e3eSDorjoy Chowdhury * key = String("range"), 779bb154e3eSDorjoy Chowdhury * value = Uint8(pcr) 780bb154e3eSDorjoy Chowdhury * } 781bb154e3eSDorjoy Chowdhury * } 782bb154e3eSDorjoy Chowdhury * } 783bb154e3eSDorjoy Chowdhury */ 784bb154e3eSDorjoy Chowdhury typedef struct NSMLockPCRsReq { 785bb154e3eSDorjoy Chowdhury uint16_t range; 786bb154e3eSDorjoy Chowdhury } NSMLockPCRsReq; 787bb154e3eSDorjoy Chowdhury 788bb154e3eSDorjoy Chowdhury static enum NSMResponseTypes get_nsm_lock_pcrs_req(uint8_t *req, size_t len, 789bb154e3eSDorjoy Chowdhury NSMLockPCRsReq *nsm_req) 790bb154e3eSDorjoy Chowdhury { 791bb154e3eSDorjoy Chowdhury cbor_item_t *item = NULL; 792bb154e3eSDorjoy Chowdhury size_t size; 793bb154e3eSDorjoy Chowdhury uint8_t *str; 794bb154e3eSDorjoy Chowdhury struct cbor_pair *pair; 795bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 796bb154e3eSDorjoy Chowdhury enum NSMResponseTypes r = NSM_INVALID_OPERATION; 797bb154e3eSDorjoy Chowdhury 798bb154e3eSDorjoy Chowdhury item = cbor_load(req, len, &result); 799bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 800bb154e3eSDorjoy Chowdhury goto cleanup; 801bb154e3eSDorjoy Chowdhury } 802bb154e3eSDorjoy Chowdhury 803bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(item); 804bb154e3eSDorjoy Chowdhury if (!cbor_isa_map(pair->value)) { 805bb154e3eSDorjoy Chowdhury goto cleanup; 806bb154e3eSDorjoy Chowdhury } 807bb154e3eSDorjoy Chowdhury size = cbor_map_size(pair->value); 808bb154e3eSDorjoy Chowdhury if (size < 1) { 809bb154e3eSDorjoy Chowdhury goto cleanup; 810bb154e3eSDorjoy Chowdhury } 811bb154e3eSDorjoy Chowdhury 812bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(pair->value); 813bb154e3eSDorjoy Chowdhury for (int i = 0; i < size; ++i) { 814bb154e3eSDorjoy Chowdhury if (!cbor_isa_string(pair[i].key)) { 815bb154e3eSDorjoy Chowdhury continue; 816bb154e3eSDorjoy Chowdhury } 817bb154e3eSDorjoy Chowdhury str = cbor_string_handle(pair[i].key); 818bb154e3eSDorjoy Chowdhury if (str && cbor_string_length(pair[i].key) == 5 && 819bb154e3eSDorjoy Chowdhury memcmp(str, "range", 5) == 0) { 820bb154e3eSDorjoy Chowdhury if (!cbor_isa_uint(pair[i].value) || 821bb154e3eSDorjoy Chowdhury cbor_int_get_width(pair[i].value) != CBOR_INT_8) { 822bb154e3eSDorjoy Chowdhury break; 823bb154e3eSDorjoy Chowdhury } 824bb154e3eSDorjoy Chowdhury 825bb154e3eSDorjoy Chowdhury nsm_req->range = cbor_get_uint8(pair[i].value); 826bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 827bb154e3eSDorjoy Chowdhury break; 828bb154e3eSDorjoy Chowdhury } 829bb154e3eSDorjoy Chowdhury } 830bb154e3eSDorjoy Chowdhury 831bb154e3eSDorjoy Chowdhury cleanup: 832bb154e3eSDorjoy Chowdhury if (item) { 833bb154e3eSDorjoy Chowdhury cbor_decref(&item); 834bb154e3eSDorjoy Chowdhury } 835bb154e3eSDorjoy Chowdhury return r; 836bb154e3eSDorjoy Chowdhury } 837bb154e3eSDorjoy Chowdhury 838bb154e3eSDorjoy Chowdhury /* 839bb154e3eSDorjoy Chowdhury * LockPCRs success response structure: 840bb154e3eSDorjoy Chowdhury * { 841bb154e3eSDorjoy Chowdhury * String("LockPCRs") 842bb154e3eSDorjoy Chowdhury * } 843bb154e3eSDorjoy Chowdhury */ 844bb154e3eSDorjoy Chowdhury static bool handle_lock_pcrs(VirtIONSM *vnsm, struct iovec *request, 845bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 846bb154e3eSDorjoy Chowdhury { 847bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 848bb154e3eSDorjoy Chowdhury size_t len; 849bb154e3eSDorjoy Chowdhury NSMLockPCRsReq nsm_req; 850bb154e3eSDorjoy Chowdhury enum NSMResponseTypes type; 851bb154e3eSDorjoy Chowdhury bool r = false; 852bb154e3eSDorjoy Chowdhury 853bb154e3eSDorjoy Chowdhury type = get_nsm_lock_pcrs_req(request->iov_base, request->iov_len, &nsm_req); 854bb154e3eSDorjoy Chowdhury if (type != NSM_SUCCESS) { 855bb154e3eSDorjoy Chowdhury if (error_response(response, type, errp)) { 856bb154e3eSDorjoy Chowdhury r = true; 857bb154e3eSDorjoy Chowdhury } 858bb154e3eSDorjoy Chowdhury goto cleanup; 859bb154e3eSDorjoy Chowdhury } 860bb154e3eSDorjoy Chowdhury if (nsm_req.range > vnsm->max_pcrs) { 861bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INVALID_INDEX, errp)) { 862bb154e3eSDorjoy Chowdhury r = true; 863bb154e3eSDorjoy Chowdhury } 864bb154e3eSDorjoy Chowdhury goto cleanup; 865bb154e3eSDorjoy Chowdhury } 866bb154e3eSDorjoy Chowdhury 867bb154e3eSDorjoy Chowdhury for (int i = 0; i < nsm_req.range; ++i) { 868bb154e3eSDorjoy Chowdhury vnsm->pcrs[i].locked = true; 869bb154e3eSDorjoy Chowdhury } 870bb154e3eSDorjoy Chowdhury 871bb154e3eSDorjoy Chowdhury root = cbor_build_string("LockPCRs"); 872bb154e3eSDorjoy Chowdhury if (!root) { 873bb154e3eSDorjoy Chowdhury goto err; 874bb154e3eSDorjoy Chowdhury } 875bb154e3eSDorjoy Chowdhury 876bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 877bb154e3eSDorjoy Chowdhury if (len == 0) { 878bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_BUFFER_TOO_SMALL, errp)) { 879bb154e3eSDorjoy Chowdhury r = true; 880bb154e3eSDorjoy Chowdhury } 881bb154e3eSDorjoy Chowdhury goto cleanup; 882bb154e3eSDorjoy Chowdhury } 883bb154e3eSDorjoy Chowdhury 884bb154e3eSDorjoy Chowdhury response->iov_len = len; 885bb154e3eSDorjoy Chowdhury r = true; 886bb154e3eSDorjoy Chowdhury goto cleanup; 887bb154e3eSDorjoy Chowdhury 888bb154e3eSDorjoy Chowdhury err: 889bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize response"); 890bb154e3eSDorjoy Chowdhury 891bb154e3eSDorjoy Chowdhury cleanup: 892bb154e3eSDorjoy Chowdhury if (root) { 893bb154e3eSDorjoy Chowdhury cbor_decref(&root); 894bb154e3eSDorjoy Chowdhury } 895bb154e3eSDorjoy Chowdhury return r; 896bb154e3eSDorjoy Chowdhury } 897bb154e3eSDorjoy Chowdhury 898bb154e3eSDorjoy Chowdhury /* 899bb154e3eSDorjoy Chowdhury * Attestation request structure: 900bb154e3eSDorjoy Chowdhury * 901bb154e3eSDorjoy Chowdhury * Map(1) { 902bb154e3eSDorjoy Chowdhury * key = String("Attestation"), 903bb154e3eSDorjoy Chowdhury * value = Map(3) { 904bb154e3eSDorjoy Chowdhury * key = String("user_data"), 905bb154e3eSDorjoy Chowdhury * value = Byte_String() || null, // Optional 906bb154e3eSDorjoy Chowdhury * key = String("nonce"), 907bb154e3eSDorjoy Chowdhury * value = Byte_String() || null, // Optional 908bb154e3eSDorjoy Chowdhury * key = String("public_key"), 909bb154e3eSDorjoy Chowdhury * value = Byte_String() || null, // Optional 910bb154e3eSDorjoy Chowdhury * } 911bb154e3eSDorjoy Chowdhury * } 912bb154e3eSDorjoy Chowdhury * } 913bb154e3eSDorjoy Chowdhury */ 914bb154e3eSDorjoy Chowdhury 915bb154e3eSDorjoy Chowdhury struct AttestationProperty { 916bb154e3eSDorjoy Chowdhury bool is_null; /* True if property is not present in map or is null */ 917bb154e3eSDorjoy Chowdhury uint16_t len; 918bb154e3eSDorjoy Chowdhury uint8_t buf[NSM_REQUEST_MAX_SIZE]; 919bb154e3eSDorjoy Chowdhury }; 920bb154e3eSDorjoy Chowdhury 921bb154e3eSDorjoy Chowdhury typedef struct NSMAttestationReq { 922bb154e3eSDorjoy Chowdhury struct AttestationProperty public_key; 923bb154e3eSDorjoy Chowdhury struct AttestationProperty user_data; 924bb154e3eSDorjoy Chowdhury struct AttestationProperty nonce; 925bb154e3eSDorjoy Chowdhury } NSMAttestationReq; 926bb154e3eSDorjoy Chowdhury 927bb154e3eSDorjoy Chowdhury static bool fill_attestation_property(struct AttestationProperty *prop, 928bb154e3eSDorjoy Chowdhury cbor_item_t *value) 929bb154e3eSDorjoy Chowdhury { 930bb154e3eSDorjoy Chowdhury uint8_t *str; 931bb154e3eSDorjoy Chowdhury bool ret = false; 932bb154e3eSDorjoy Chowdhury 933bb154e3eSDorjoy Chowdhury if (cbor_is_null(value)) { 934bb154e3eSDorjoy Chowdhury prop->is_null = true; 935bb154e3eSDorjoy Chowdhury ret = true; 936bb154e3eSDorjoy Chowdhury goto out; 937bb154e3eSDorjoy Chowdhury } else if (cbor_isa_bytestring(value)) { 938bb154e3eSDorjoy Chowdhury str = cbor_bytestring_handle(value); 939bb154e3eSDorjoy Chowdhury if (!str) { 940bb154e3eSDorjoy Chowdhury goto out; 941bb154e3eSDorjoy Chowdhury } 942bb154e3eSDorjoy Chowdhury prop->len = cbor_bytestring_length(value); 943bb154e3eSDorjoy Chowdhury } else if (cbor_isa_string(value)) { 944bb154e3eSDorjoy Chowdhury str = cbor_string_handle(value); 945bb154e3eSDorjoy Chowdhury if (!str) { 946bb154e3eSDorjoy Chowdhury goto out; 947bb154e3eSDorjoy Chowdhury } 948bb154e3eSDorjoy Chowdhury prop->len = cbor_string_length(value); 949bb154e3eSDorjoy Chowdhury } else { 950bb154e3eSDorjoy Chowdhury goto out; 951bb154e3eSDorjoy Chowdhury } 952bb154e3eSDorjoy Chowdhury 953bb154e3eSDorjoy Chowdhury /* 954bb154e3eSDorjoy Chowdhury * prop->len will be smaller than NSM_REQUEST_MAX_SIZE as we 955bb154e3eSDorjoy Chowdhury * already check for the max request size before processing 956bb154e3eSDorjoy Chowdhury * any request. So it's safe to copy. 957bb154e3eSDorjoy Chowdhury */ 958bb154e3eSDorjoy Chowdhury memcpy(prop->buf, str, prop->len); 959bb154e3eSDorjoy Chowdhury prop->is_null = false; 960bb154e3eSDorjoy Chowdhury ret = true; 961bb154e3eSDorjoy Chowdhury 962bb154e3eSDorjoy Chowdhury out: 963bb154e3eSDorjoy Chowdhury return ret; 964bb154e3eSDorjoy Chowdhury } 965bb154e3eSDorjoy Chowdhury 966bb154e3eSDorjoy Chowdhury static enum NSMResponseTypes get_nsm_attestation_req(uint8_t *req, size_t len, 967bb154e3eSDorjoy Chowdhury NSMAttestationReq *nsm_req) 968bb154e3eSDorjoy Chowdhury { 969bb154e3eSDorjoy Chowdhury cbor_item_t *item = NULL; 970bb154e3eSDorjoy Chowdhury size_t size; 971bb154e3eSDorjoy Chowdhury uint8_t *str; 972bb154e3eSDorjoy Chowdhury struct cbor_pair *pair; 973bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 974bb154e3eSDorjoy Chowdhury enum NSMResponseTypes r = NSM_INVALID_OPERATION; 975bb154e3eSDorjoy Chowdhury 976bb154e3eSDorjoy Chowdhury nsm_req->public_key.is_null = true; 977bb154e3eSDorjoy Chowdhury nsm_req->user_data.is_null = true; 978bb154e3eSDorjoy Chowdhury nsm_req->nonce.is_null = true; 979bb154e3eSDorjoy Chowdhury 980bb154e3eSDorjoy Chowdhury item = cbor_load(req, len, &result); 981bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 982bb154e3eSDorjoy Chowdhury goto cleanup; 983bb154e3eSDorjoy Chowdhury } 984bb154e3eSDorjoy Chowdhury 985bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(item); 986bb154e3eSDorjoy Chowdhury if (!cbor_isa_map(pair->value)) { 987bb154e3eSDorjoy Chowdhury goto cleanup; 988bb154e3eSDorjoy Chowdhury } 989bb154e3eSDorjoy Chowdhury size = cbor_map_size(pair->value); 990bb154e3eSDorjoy Chowdhury if (size == 0) { 991bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 992bb154e3eSDorjoy Chowdhury goto cleanup; 993bb154e3eSDorjoy Chowdhury } 994bb154e3eSDorjoy Chowdhury 995bb154e3eSDorjoy Chowdhury pair = cbor_map_handle(pair->value); 996bb154e3eSDorjoy Chowdhury for (int i = 0; i < size; ++i) { 997bb154e3eSDorjoy Chowdhury if (!cbor_isa_string(pair[i].key)) { 998bb154e3eSDorjoy Chowdhury continue; 999bb154e3eSDorjoy Chowdhury } 1000bb154e3eSDorjoy Chowdhury 1001bb154e3eSDorjoy Chowdhury str = cbor_string_handle(pair[i].key); 1002bb154e3eSDorjoy Chowdhury if (!str) { 1003bb154e3eSDorjoy Chowdhury continue; 1004bb154e3eSDorjoy Chowdhury } 1005bb154e3eSDorjoy Chowdhury 1006bb154e3eSDorjoy Chowdhury if (cbor_string_length(pair[i].key) == 10 && 1007bb154e3eSDorjoy Chowdhury memcmp(str, "public_key", 10) == 0) { 1008bb154e3eSDorjoy Chowdhury if (!fill_attestation_property(&(nsm_req->public_key), 1009bb154e3eSDorjoy Chowdhury pair[i].value)) { 1010bb154e3eSDorjoy Chowdhury goto cleanup; 1011bb154e3eSDorjoy Chowdhury } 1012bb154e3eSDorjoy Chowdhury continue; 1013bb154e3eSDorjoy Chowdhury } 1014bb154e3eSDorjoy Chowdhury 1015bb154e3eSDorjoy Chowdhury if (cbor_string_length(pair[i].key) == 9 && 1016bb154e3eSDorjoy Chowdhury memcmp(str, "user_data", 9) == 0) { 1017bb154e3eSDorjoy Chowdhury if (!fill_attestation_property(&(nsm_req->user_data), 1018bb154e3eSDorjoy Chowdhury pair[i].value)) { 1019bb154e3eSDorjoy Chowdhury goto cleanup; 1020bb154e3eSDorjoy Chowdhury } 1021bb154e3eSDorjoy Chowdhury continue; 1022bb154e3eSDorjoy Chowdhury } 1023bb154e3eSDorjoy Chowdhury 1024bb154e3eSDorjoy Chowdhury if (cbor_string_length(pair[i].key) == 5 && 1025bb154e3eSDorjoy Chowdhury memcmp(str, "nonce", 5) == 0) { 1026bb154e3eSDorjoy Chowdhury if (!fill_attestation_property(&(nsm_req->nonce), pair[i].value)) { 1027bb154e3eSDorjoy Chowdhury goto cleanup; 1028bb154e3eSDorjoy Chowdhury } 1029bb154e3eSDorjoy Chowdhury continue; 1030bb154e3eSDorjoy Chowdhury } 1031bb154e3eSDorjoy Chowdhury } 1032bb154e3eSDorjoy Chowdhury 1033bb154e3eSDorjoy Chowdhury r = NSM_SUCCESS; 1034bb154e3eSDorjoy Chowdhury 1035bb154e3eSDorjoy Chowdhury cleanup: 1036bb154e3eSDorjoy Chowdhury if (item) { 1037bb154e3eSDorjoy Chowdhury cbor_decref(&item); 1038bb154e3eSDorjoy Chowdhury } 1039bb154e3eSDorjoy Chowdhury return r; 1040bb154e3eSDorjoy Chowdhury } 1041bb154e3eSDorjoy Chowdhury 1042bb154e3eSDorjoy Chowdhury static bool add_protected_header_to_cose(cbor_item_t *cose) 1043bb154e3eSDorjoy Chowdhury { 1044bb154e3eSDorjoy Chowdhury cbor_item_t *map = NULL; 1045bb154e3eSDorjoy Chowdhury cbor_item_t *key = NULL; 1046bb154e3eSDorjoy Chowdhury cbor_item_t *value = NULL; 1047bb154e3eSDorjoy Chowdhury cbor_item_t *bs = NULL; 1048bb154e3eSDorjoy Chowdhury size_t len; 1049bb154e3eSDorjoy Chowdhury bool r = false; 1050bb154e3eSDorjoy Chowdhury size_t buf_len = 4096; 1051bb154e3eSDorjoy Chowdhury g_autofree uint8_t *buf = g_malloc(buf_len); 1052bb154e3eSDorjoy Chowdhury 1053bb154e3eSDorjoy Chowdhury map = cbor_new_definite_map(1); 1054bb154e3eSDorjoy Chowdhury if (!map) { 1055bb154e3eSDorjoy Chowdhury goto cleanup; 1056bb154e3eSDorjoy Chowdhury } 1057bb154e3eSDorjoy Chowdhury key = cbor_build_uint8(1); 1058bb154e3eSDorjoy Chowdhury if (!key) { 1059bb154e3eSDorjoy Chowdhury goto cleanup; 1060bb154e3eSDorjoy Chowdhury } 1061bb154e3eSDorjoy Chowdhury value = cbor_new_int8(); 1062bb154e3eSDorjoy Chowdhury if (!value) { 1063bb154e3eSDorjoy Chowdhury goto cleanup; 1064bb154e3eSDorjoy Chowdhury } 1065bb154e3eSDorjoy Chowdhury cbor_mark_negint(value); 1066bb154e3eSDorjoy Chowdhury /* we don't actually sign the data, so we use -1 as the 'alg' value */ 1067bb154e3eSDorjoy Chowdhury cbor_set_uint8(value, 0); 1068bb154e3eSDorjoy Chowdhury 1069bb154e3eSDorjoy Chowdhury if (!qemu_cbor_map_add(map, key, value)) { 1070bb154e3eSDorjoy Chowdhury goto cleanup; 1071bb154e3eSDorjoy Chowdhury } 1072bb154e3eSDorjoy Chowdhury 1073bb154e3eSDorjoy Chowdhury len = cbor_serialize(map, buf, buf_len); 1074bb154e3eSDorjoy Chowdhury if (len == 0) { 1075bb154e3eSDorjoy Chowdhury goto cleanup_map; 1076bb154e3eSDorjoy Chowdhury } 1077bb154e3eSDorjoy Chowdhury 1078bb154e3eSDorjoy Chowdhury bs = cbor_build_bytestring(buf, len); 1079bb154e3eSDorjoy Chowdhury if (!bs) { 1080bb154e3eSDorjoy Chowdhury goto cleanup_map; 1081bb154e3eSDorjoy Chowdhury } 1082bb154e3eSDorjoy Chowdhury if (!qemu_cbor_array_push(cose, bs)) { 1083bb154e3eSDorjoy Chowdhury cbor_decref(&bs); 1084bb154e3eSDorjoy Chowdhury goto cleanup_map; 1085bb154e3eSDorjoy Chowdhury } 1086bb154e3eSDorjoy Chowdhury r = true; 1087bb154e3eSDorjoy Chowdhury goto cleanup_map; 1088bb154e3eSDorjoy Chowdhury 1089bb154e3eSDorjoy Chowdhury cleanup: 1090bb154e3eSDorjoy Chowdhury if (key) { 1091bb154e3eSDorjoy Chowdhury cbor_decref(&key); 1092bb154e3eSDorjoy Chowdhury } 1093bb154e3eSDorjoy Chowdhury if (value) { 1094bb154e3eSDorjoy Chowdhury cbor_decref(&value); 1095bb154e3eSDorjoy Chowdhury } 1096bb154e3eSDorjoy Chowdhury 1097bb154e3eSDorjoy Chowdhury cleanup_map: 1098bb154e3eSDorjoy Chowdhury if (map) { 1099bb154e3eSDorjoy Chowdhury cbor_decref(&map); 1100bb154e3eSDorjoy Chowdhury } 1101bb154e3eSDorjoy Chowdhury return r; 1102bb154e3eSDorjoy Chowdhury } 1103bb154e3eSDorjoy Chowdhury 1104bb154e3eSDorjoy Chowdhury static bool add_unprotected_header_to_cose(cbor_item_t *cose) 1105bb154e3eSDorjoy Chowdhury { 1106bb154e3eSDorjoy Chowdhury cbor_item_t *map = cbor_new_definite_map(0); 1107bb154e3eSDorjoy Chowdhury if (!map) { 1108bb154e3eSDorjoy Chowdhury goto cleanup; 1109bb154e3eSDorjoy Chowdhury } 1110bb154e3eSDorjoy Chowdhury if (!qemu_cbor_array_push(cose, map)) { 1111bb154e3eSDorjoy Chowdhury goto cleanup; 1112bb154e3eSDorjoy Chowdhury } 1113bb154e3eSDorjoy Chowdhury 1114bb154e3eSDorjoy Chowdhury return true; 1115bb154e3eSDorjoy Chowdhury 1116bb154e3eSDorjoy Chowdhury cleanup: 1117bb154e3eSDorjoy Chowdhury if (map) { 1118bb154e3eSDorjoy Chowdhury cbor_decref(&map); 1119bb154e3eSDorjoy Chowdhury } 1120bb154e3eSDorjoy Chowdhury return false; 1121bb154e3eSDorjoy Chowdhury } 1122bb154e3eSDorjoy Chowdhury 1123bb154e3eSDorjoy Chowdhury static bool add_ca_bundle_to_payload(cbor_item_t *map) 1124bb154e3eSDorjoy Chowdhury { 1125bb154e3eSDorjoy Chowdhury cbor_item_t *key_cbor = NULL; 1126bb154e3eSDorjoy Chowdhury cbor_item_t *value_cbor = NULL; 1127bb154e3eSDorjoy Chowdhury cbor_item_t *bs = NULL; 1128bb154e3eSDorjoy Chowdhury uint8_t zero[64] = {0}; 1129bb154e3eSDorjoy Chowdhury 1130bb154e3eSDorjoy Chowdhury key_cbor = cbor_build_string("cabundle"); 1131bb154e3eSDorjoy Chowdhury if (!key_cbor) { 1132bb154e3eSDorjoy Chowdhury goto cleanup; 1133bb154e3eSDorjoy Chowdhury } 1134bb154e3eSDorjoy Chowdhury value_cbor = cbor_new_definite_array(1); 1135bb154e3eSDorjoy Chowdhury if (!value_cbor) { 1136bb154e3eSDorjoy Chowdhury goto cleanup; 1137bb154e3eSDorjoy Chowdhury } 1138bb154e3eSDorjoy Chowdhury bs = cbor_build_bytestring(zero, 64); 1139bb154e3eSDorjoy Chowdhury if (!bs) { 1140bb154e3eSDorjoy Chowdhury goto cleanup; 1141bb154e3eSDorjoy Chowdhury } 1142bb154e3eSDorjoy Chowdhury if (!qemu_cbor_array_push(value_cbor, bs)) { 1143bb154e3eSDorjoy Chowdhury cbor_decref(&bs); 1144bb154e3eSDorjoy Chowdhury goto cleanup; 1145bb154e3eSDorjoy Chowdhury } 1146bb154e3eSDorjoy Chowdhury if (!qemu_cbor_map_add(map, key_cbor, value_cbor)) { 1147bb154e3eSDorjoy Chowdhury goto cleanup; 1148bb154e3eSDorjoy Chowdhury } 1149bb154e3eSDorjoy Chowdhury 1150bb154e3eSDorjoy Chowdhury return true; 1151bb154e3eSDorjoy Chowdhury 1152bb154e3eSDorjoy Chowdhury cleanup: 1153bb154e3eSDorjoy Chowdhury if (key_cbor) { 1154bb154e3eSDorjoy Chowdhury cbor_decref(&key_cbor); 1155bb154e3eSDorjoy Chowdhury } 1156bb154e3eSDorjoy Chowdhury if (value_cbor) { 1157bb154e3eSDorjoy Chowdhury cbor_decref(&value_cbor); 1158bb154e3eSDorjoy Chowdhury } 1159bb154e3eSDorjoy Chowdhury return false; 1160bb154e3eSDorjoy Chowdhury } 1161bb154e3eSDorjoy Chowdhury 1162bb154e3eSDorjoy Chowdhury static bool add_payload_to_cose(cbor_item_t *cose, VirtIONSM *vnsm, 1163bb154e3eSDorjoy Chowdhury NSMAttestationReq *req) 1164bb154e3eSDorjoy Chowdhury { 1165bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 1166bb154e3eSDorjoy Chowdhury cbor_item_t *nested_map; 1167bb154e3eSDorjoy Chowdhury cbor_item_t *bs = NULL; 1168bb154e3eSDorjoy Chowdhury size_t locked_cnt; 1169bb154e3eSDorjoy Chowdhury uint8_t ind[NSM_MAX_PCRS]; 1170bb154e3eSDorjoy Chowdhury size_t payload_map_size = 9; 1171bb154e3eSDorjoy Chowdhury size_t len; 1172bb154e3eSDorjoy Chowdhury struct PCRInfo *pcr; 1173bb154e3eSDorjoy Chowdhury uint8_t zero[64] = {0}; 1174bb154e3eSDorjoy Chowdhury bool r = false; 1175bb154e3eSDorjoy Chowdhury size_t buf_len = 16384; 1176bb154e3eSDorjoy Chowdhury g_autofree uint8_t *buf = g_malloc(buf_len); 1177bb154e3eSDorjoy Chowdhury 1178bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(payload_map_size); 1179bb154e3eSDorjoy Chowdhury if (!root) { 1180bb154e3eSDorjoy Chowdhury goto cleanup; 1181bb154e3eSDorjoy Chowdhury } 1182bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_string_to_map(root, "module_id", vnsm->module_id)) { 1183bb154e3eSDorjoy Chowdhury goto cleanup; 1184bb154e3eSDorjoy Chowdhury } 1185bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_string_to_map(root, "digest", vnsm->digest)) { 1186bb154e3eSDorjoy Chowdhury goto cleanup; 1187bb154e3eSDorjoy Chowdhury } 1188bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint64_to_map(root, "timestamp", 1189bb154e3eSDorjoy Chowdhury (uint64_t) time(NULL) * 1000)) { 1190bb154e3eSDorjoy Chowdhury goto cleanup; 1191bb154e3eSDorjoy Chowdhury } 1192bb154e3eSDorjoy Chowdhury 1193bb154e3eSDorjoy Chowdhury locked_cnt = 0; 1194bb154e3eSDorjoy Chowdhury for (uint8_t i = 0; i < NSM_MAX_PCRS; ++i) { 1195bb154e3eSDorjoy Chowdhury if (vnsm->pcrs[i].locked) { 1196bb154e3eSDorjoy Chowdhury ind[locked_cnt++] = i; 1197bb154e3eSDorjoy Chowdhury } 1198bb154e3eSDorjoy Chowdhury } 1199bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "pcrs", locked_cnt, &nested_map)) { 1200bb154e3eSDorjoy Chowdhury goto cleanup; 1201bb154e3eSDorjoy Chowdhury } 1202bb154e3eSDorjoy Chowdhury for (uint8_t i = 0; i < locked_cnt; ++i) { 1203bb154e3eSDorjoy Chowdhury pcr = &(vnsm->pcrs[ind[i]]); 1204bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_uint8_key_bytestring_to_map( 1205bb154e3eSDorjoy Chowdhury nested_map, ind[i], 1206bb154e3eSDorjoy Chowdhury pcr->data, 1207bb154e3eSDorjoy Chowdhury QCRYPTO_HASH_DIGEST_LEN_SHA384)) { 1208bb154e3eSDorjoy Chowdhury goto cleanup; 1209bb154e3eSDorjoy Chowdhury } 1210bb154e3eSDorjoy Chowdhury } 1211bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bytestring_to_map(root, "certificate", zero, 64)) { 1212bb154e3eSDorjoy Chowdhury goto cleanup; 1213bb154e3eSDorjoy Chowdhury } 1214bb154e3eSDorjoy Chowdhury if (!add_ca_bundle_to_payload(root)) { 1215bb154e3eSDorjoy Chowdhury goto cleanup; 1216bb154e3eSDorjoy Chowdhury } 1217bb154e3eSDorjoy Chowdhury 1218bb154e3eSDorjoy Chowdhury if (req->public_key.is_null) { 1219bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_null_to_map(root, "public_key")) { 1220bb154e3eSDorjoy Chowdhury goto cleanup; 1221bb154e3eSDorjoy Chowdhury } 1222bb154e3eSDorjoy Chowdhury } else if (!qemu_cbor_add_bytestring_to_map(root, "public_key", 1223bb154e3eSDorjoy Chowdhury req->public_key.buf, 1224bb154e3eSDorjoy Chowdhury req->public_key.len)) { 1225bb154e3eSDorjoy Chowdhury goto cleanup; 1226bb154e3eSDorjoy Chowdhury } 1227bb154e3eSDorjoy Chowdhury 1228bb154e3eSDorjoy Chowdhury if (req->user_data.is_null) { 1229bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_null_to_map(root, "user_data")) { 1230bb154e3eSDorjoy Chowdhury goto cleanup; 1231bb154e3eSDorjoy Chowdhury } 1232bb154e3eSDorjoy Chowdhury } else if (!qemu_cbor_add_bytestring_to_map(root, "user_data", 1233bb154e3eSDorjoy Chowdhury req->user_data.buf, 1234bb154e3eSDorjoy Chowdhury req->user_data.len)) { 1235bb154e3eSDorjoy Chowdhury goto cleanup; 1236bb154e3eSDorjoy Chowdhury } 1237bb154e3eSDorjoy Chowdhury 1238bb154e3eSDorjoy Chowdhury if (req->nonce.is_null) { 1239bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_null_to_map(root, "nonce")) { 1240bb154e3eSDorjoy Chowdhury goto cleanup; 1241bb154e3eSDorjoy Chowdhury } 1242bb154e3eSDorjoy Chowdhury } else if (!qemu_cbor_add_bytestring_to_map(root, "nonce", 1243bb154e3eSDorjoy Chowdhury req->nonce.buf, 1244bb154e3eSDorjoy Chowdhury req->nonce.len)) { 1245bb154e3eSDorjoy Chowdhury goto cleanup; 1246bb154e3eSDorjoy Chowdhury } 1247bb154e3eSDorjoy Chowdhury 1248bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, buf, buf_len); 1249bb154e3eSDorjoy Chowdhury if (len == 0) { 1250bb154e3eSDorjoy Chowdhury goto cleanup; 1251bb154e3eSDorjoy Chowdhury } 1252bb154e3eSDorjoy Chowdhury 1253bb154e3eSDorjoy Chowdhury bs = cbor_build_bytestring(buf, len); 1254bb154e3eSDorjoy Chowdhury if (!bs) { 1255bb154e3eSDorjoy Chowdhury goto cleanup; 1256bb154e3eSDorjoy Chowdhury } 1257bb154e3eSDorjoy Chowdhury if (!qemu_cbor_array_push(cose, bs)) { 1258bb154e3eSDorjoy Chowdhury cbor_decref(&bs); 1259bb154e3eSDorjoy Chowdhury goto cleanup; 1260bb154e3eSDorjoy Chowdhury } 1261bb154e3eSDorjoy Chowdhury 1262bb154e3eSDorjoy Chowdhury r = true; 1263bb154e3eSDorjoy Chowdhury 1264bb154e3eSDorjoy Chowdhury cleanup: 1265bb154e3eSDorjoy Chowdhury if (root) { 1266bb154e3eSDorjoy Chowdhury cbor_decref(&root); 1267bb154e3eSDorjoy Chowdhury } 1268bb154e3eSDorjoy Chowdhury return r; 1269bb154e3eSDorjoy Chowdhury } 1270bb154e3eSDorjoy Chowdhury 1271bb154e3eSDorjoy Chowdhury static bool add_signature_to_cose(cbor_item_t *cose) 1272bb154e3eSDorjoy Chowdhury { 1273bb154e3eSDorjoy Chowdhury cbor_item_t *bs = NULL; 1274bb154e3eSDorjoy Chowdhury uint8_t zero[64] = {0}; 1275bb154e3eSDorjoy Chowdhury 1276bb154e3eSDorjoy Chowdhury /* we don't actually sign the data, so we just put 64 zero bytes */ 1277bb154e3eSDorjoy Chowdhury bs = cbor_build_bytestring(zero, 64); 1278bb154e3eSDorjoy Chowdhury if (!bs) { 1279bb154e3eSDorjoy Chowdhury goto cleanup; 1280bb154e3eSDorjoy Chowdhury } 1281bb154e3eSDorjoy Chowdhury 1282bb154e3eSDorjoy Chowdhury if (!qemu_cbor_array_push(cose, bs)) { 1283bb154e3eSDorjoy Chowdhury goto cleanup; 1284bb154e3eSDorjoy Chowdhury } 1285bb154e3eSDorjoy Chowdhury 1286bb154e3eSDorjoy Chowdhury return true; 1287bb154e3eSDorjoy Chowdhury 1288bb154e3eSDorjoy Chowdhury cleanup: 1289bb154e3eSDorjoy Chowdhury if (bs) { 1290bb154e3eSDorjoy Chowdhury cbor_decref(&bs); 1291bb154e3eSDorjoy Chowdhury } 1292bb154e3eSDorjoy Chowdhury return false; 1293bb154e3eSDorjoy Chowdhury } 1294bb154e3eSDorjoy Chowdhury 1295bb154e3eSDorjoy Chowdhury /* 1296bb154e3eSDorjoy Chowdhury * Attestation response structure: 1297bb154e3eSDorjoy Chowdhury * 1298bb154e3eSDorjoy Chowdhury * { 1299bb154e3eSDorjoy Chowdhury * Map(1) { 1300bb154e3eSDorjoy Chowdhury * key = String("Attestation"), 1301bb154e3eSDorjoy Chowdhury * value = Map(1) { 1302bb154e3eSDorjoy Chowdhury * key = String("document"), 1303bb154e3eSDorjoy Chowdhury * value = Byte_String() 1304bb154e3eSDorjoy Chowdhury * } 1305bb154e3eSDorjoy Chowdhury * } 1306bb154e3eSDorjoy Chowdhury * } 1307bb154e3eSDorjoy Chowdhury * 1308bb154e3eSDorjoy Chowdhury * The document is a serialized COSE sign1 blob of the structure: 1309bb154e3eSDorjoy Chowdhury * { 1310bb154e3eSDorjoy Chowdhury * Array(4) { 1311bb154e3eSDorjoy Chowdhury * [0] { ByteString() }, // serialized protected header 1312bb154e3eSDorjoy Chowdhury * [1] { Map(0) }, // 0 length map 1313bb154e3eSDorjoy Chowdhury * [2] { ByteString() }, // serialized payload 1314bb154e3eSDorjoy Chowdhury * [3] { ByteString() }, // signature 1315bb154e3eSDorjoy Chowdhury * } 1316bb154e3eSDorjoy Chowdhury * } 1317bb154e3eSDorjoy Chowdhury * 1318bb154e3eSDorjoy Chowdhury * where [0] protected header is a serialized CBOR blob of the structure: 1319bb154e3eSDorjoy Chowdhury * { 1320bb154e3eSDorjoy Chowdhury * Map(1) { 1321bb154e3eSDorjoy Chowdhury * key = Uint8(1) // alg 1322bb154e3eSDorjoy Chowdhury * value = NegativeInt8() // Signing algorithm 1323bb154e3eSDorjoy Chowdhury * } 1324bb154e3eSDorjoy Chowdhury * } 1325bb154e3eSDorjoy Chowdhury * 1326bb154e3eSDorjoy Chowdhury * [2] payload is serialized CBOR blob of the structure: 1327bb154e3eSDorjoy Chowdhury * { 1328bb154e3eSDorjoy Chowdhury * Map(9) { 1329bb154e3eSDorjoy Chowdhury * [0] { key = String("module_id"), value = String(module_id) }, 1330bb154e3eSDorjoy Chowdhury * [1] { key = String("digest"), value = String("SHA384") }, 1331bb154e3eSDorjoy Chowdhury * [2] { 1332bb154e3eSDorjoy Chowdhury * key = String("timestamp"), 1333bb154e3eSDorjoy Chowdhury * value = Uint64(unix epoch of when document was created) 1334bb154e3eSDorjoy Chowdhury * }, 1335bb154e3eSDorjoy Chowdhury * [3] { 1336bb154e3eSDorjoy Chowdhury * key = String("pcrs"), 1337bb154e3eSDorjoy Chowdhury * value = Map(locked_pcr_cnt) { 1338bb154e3eSDorjoy Chowdhury * key = Uint8(pcr_index), 1339bb154e3eSDorjoy Chowdhury * value = ByteString(pcr_data) 1340bb154e3eSDorjoy Chowdhury * }, 1341bb154e3eSDorjoy Chowdhury * }, 1342bb154e3eSDorjoy Chowdhury * [4] { 1343bb154e3eSDorjoy Chowdhury * key = String("certificate"), 1344bb154e3eSDorjoy Chowdhury * value = ByteString(Signing certificate) 1345bb154e3eSDorjoy Chowdhury * }, 1346bb154e3eSDorjoy Chowdhury * [5] { key = String("cabundle"), value = Array(N) { ByteString()... } }, 1347bb154e3eSDorjoy Chowdhury * [6] { key = String("public_key"), value = ByteString() || null }, 1348bb154e3eSDorjoy Chowdhury * [7] { key = String("user_data"), value = ByteString() || null}, 1349bb154e3eSDorjoy Chowdhury * [8] { key = String("nonce"), value = ByteString() || null}, 1350bb154e3eSDorjoy Chowdhury * } 1351bb154e3eSDorjoy Chowdhury * } 1352bb154e3eSDorjoy Chowdhury */ 1353bb154e3eSDorjoy Chowdhury static bool handle_attestation(VirtIONSM *vnsm, struct iovec *request, 1354bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp) 1355bb154e3eSDorjoy Chowdhury { 1356bb154e3eSDorjoy Chowdhury cbor_item_t *root = NULL; 1357bb154e3eSDorjoy Chowdhury cbor_item_t *cose = NULL; 1358bb154e3eSDorjoy Chowdhury cbor_item_t *nested_map; 1359bb154e3eSDorjoy Chowdhury size_t len; 1360bb154e3eSDorjoy Chowdhury enum NSMResponseTypes type; 1361bb154e3eSDorjoy Chowdhury bool r = false; 1362bb154e3eSDorjoy Chowdhury size_t buf_len = 16384; 1363bb154e3eSDorjoy Chowdhury g_autofree uint8_t *buf = g_malloc(buf_len); 1364bb154e3eSDorjoy Chowdhury g_autofree NSMAttestationReq *nsm_req = g_malloc(sizeof(NSMAttestationReq)); 1365bb154e3eSDorjoy Chowdhury 1366bb154e3eSDorjoy Chowdhury nsm_req->public_key.is_null = true; 1367bb154e3eSDorjoy Chowdhury nsm_req->user_data.is_null = true; 1368bb154e3eSDorjoy Chowdhury nsm_req->nonce.is_null = true; 1369bb154e3eSDorjoy Chowdhury 1370bb154e3eSDorjoy Chowdhury type = get_nsm_attestation_req(request->iov_base, request->iov_len, 1371bb154e3eSDorjoy Chowdhury nsm_req); 1372bb154e3eSDorjoy Chowdhury if (type != NSM_SUCCESS) { 1373bb154e3eSDorjoy Chowdhury if (error_response(response, type, errp)) { 1374bb154e3eSDorjoy Chowdhury r = true; 1375bb154e3eSDorjoy Chowdhury } 1376bb154e3eSDorjoy Chowdhury goto out; 1377bb154e3eSDorjoy Chowdhury } 1378bb154e3eSDorjoy Chowdhury 1379bb154e3eSDorjoy Chowdhury cose = cbor_new_definite_array(4); 1380bb154e3eSDorjoy Chowdhury if (!cose) { 1381bb154e3eSDorjoy Chowdhury goto err; 1382bb154e3eSDorjoy Chowdhury } 1383bb154e3eSDorjoy Chowdhury if (!add_protected_header_to_cose(cose)) { 1384bb154e3eSDorjoy Chowdhury goto err; 1385bb154e3eSDorjoy Chowdhury } 1386bb154e3eSDorjoy Chowdhury if (!add_unprotected_header_to_cose(cose)) { 1387bb154e3eSDorjoy Chowdhury goto err; 1388bb154e3eSDorjoy Chowdhury } 1389bb154e3eSDorjoy Chowdhury if (!add_payload_to_cose(cose, vnsm, nsm_req)) { 1390bb154e3eSDorjoy Chowdhury goto err; 1391bb154e3eSDorjoy Chowdhury } 1392bb154e3eSDorjoy Chowdhury if (!add_signature_to_cose(cose)) { 1393bb154e3eSDorjoy Chowdhury goto err; 1394bb154e3eSDorjoy Chowdhury } 1395bb154e3eSDorjoy Chowdhury 1396bb154e3eSDorjoy Chowdhury len = cbor_serialize(cose, buf, buf_len); 1397bb154e3eSDorjoy Chowdhury if (len == 0) { 1398bb154e3eSDorjoy Chowdhury goto err; 1399bb154e3eSDorjoy Chowdhury } 1400bb154e3eSDorjoy Chowdhury 1401bb154e3eSDorjoy Chowdhury root = cbor_new_definite_map(1); 1402bb154e3eSDorjoy Chowdhury if (!root) { 1403bb154e3eSDorjoy Chowdhury goto err; 1404bb154e3eSDorjoy Chowdhury } 1405bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_map_to_map(root, "Attestation", 1, &nested_map)) { 1406bb154e3eSDorjoy Chowdhury goto err; 1407bb154e3eSDorjoy Chowdhury } 1408bb154e3eSDorjoy Chowdhury if (!qemu_cbor_add_bytestring_to_map(nested_map, "document", buf, len)) { 1409bb154e3eSDorjoy Chowdhury goto err; 1410bb154e3eSDorjoy Chowdhury } 1411bb154e3eSDorjoy Chowdhury 1412bb154e3eSDorjoy Chowdhury len = cbor_serialize(root, response->iov_base, response->iov_len); 1413bb154e3eSDorjoy Chowdhury if (len == 0) { 1414bb154e3eSDorjoy Chowdhury if (error_response(response, NSM_INPUT_TOO_LARGE, errp)) { 1415bb154e3eSDorjoy Chowdhury r = true; 1416bb154e3eSDorjoy Chowdhury } 1417bb154e3eSDorjoy Chowdhury goto out; 1418bb154e3eSDorjoy Chowdhury } 1419bb154e3eSDorjoy Chowdhury 1420bb154e3eSDorjoy Chowdhury response->iov_len = len; 1421bb154e3eSDorjoy Chowdhury r = true; 1422bb154e3eSDorjoy Chowdhury 1423bb154e3eSDorjoy Chowdhury out: 1424bb154e3eSDorjoy Chowdhury if (root) { 1425bb154e3eSDorjoy Chowdhury cbor_decref(&root); 1426bb154e3eSDorjoy Chowdhury } 1427bb154e3eSDorjoy Chowdhury if (cose) { 1428bb154e3eSDorjoy Chowdhury cbor_decref(&cose); 1429bb154e3eSDorjoy Chowdhury } 1430bb154e3eSDorjoy Chowdhury return r; 1431bb154e3eSDorjoy Chowdhury 1432bb154e3eSDorjoy Chowdhury err: 1433bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize Attestation response"); 1434bb154e3eSDorjoy Chowdhury goto out; 1435bb154e3eSDorjoy Chowdhury } 1436bb154e3eSDorjoy Chowdhury 1437bb154e3eSDorjoy Chowdhury enum CBOR_ROOT_TYPE { 1438bb154e3eSDorjoy Chowdhury CBOR_ROOT_TYPE_STRING = 0, 1439bb154e3eSDorjoy Chowdhury CBOR_ROOT_TYPE_MAP = 1, 1440bb154e3eSDorjoy Chowdhury }; 1441bb154e3eSDorjoy Chowdhury 1442bb154e3eSDorjoy Chowdhury struct nsm_cmd { 1443bb154e3eSDorjoy Chowdhury char name[16]; 1444bb154e3eSDorjoy Chowdhury /* 1445bb154e3eSDorjoy Chowdhury * There are 2 types of request 1446bb154e3eSDorjoy Chowdhury * 1) String(); "GetRandom", "DescribeNSM" 1447bb154e3eSDorjoy Chowdhury * 2) Map(1) { key: String(), value: ... } 1448bb154e3eSDorjoy Chowdhury */ 1449bb154e3eSDorjoy Chowdhury enum CBOR_ROOT_TYPE root_type; 1450bb154e3eSDorjoy Chowdhury bool (*response_fn)(VirtIONSM *vnsm, struct iovec *request, 1451bb154e3eSDorjoy Chowdhury struct iovec *response, Error **errp); 1452bb154e3eSDorjoy Chowdhury }; 1453bb154e3eSDorjoy Chowdhury 1454bb154e3eSDorjoy Chowdhury const struct nsm_cmd nsm_cmds[] = { 1455bb154e3eSDorjoy Chowdhury { "GetRandom", CBOR_ROOT_TYPE_STRING, handle_get_random }, 1456bb154e3eSDorjoy Chowdhury { "DescribeNSM", CBOR_ROOT_TYPE_STRING, handle_describe_nsm }, 1457bb154e3eSDorjoy Chowdhury { "DescribePCR", CBOR_ROOT_TYPE_MAP, handle_describe_pcr }, 1458bb154e3eSDorjoy Chowdhury { "ExtendPCR", CBOR_ROOT_TYPE_MAP, handle_extend_pcr }, 1459bb154e3eSDorjoy Chowdhury { "LockPCR", CBOR_ROOT_TYPE_MAP, handle_lock_pcr }, 1460bb154e3eSDorjoy Chowdhury { "LockPCRs", CBOR_ROOT_TYPE_MAP, handle_lock_pcrs }, 1461bb154e3eSDorjoy Chowdhury { "Attestation", CBOR_ROOT_TYPE_MAP, handle_attestation }, 1462bb154e3eSDorjoy Chowdhury }; 1463bb154e3eSDorjoy Chowdhury 1464bb154e3eSDorjoy Chowdhury static const struct nsm_cmd *get_nsm_request_cmd(uint8_t *buf, size_t len) 1465bb154e3eSDorjoy Chowdhury { 1466bb154e3eSDorjoy Chowdhury size_t size; 1467bb154e3eSDorjoy Chowdhury uint8_t *req; 1468bb154e3eSDorjoy Chowdhury enum CBOR_ROOT_TYPE root_type; 1469bb154e3eSDorjoy Chowdhury struct cbor_load_result result; 1470bb154e3eSDorjoy Chowdhury cbor_item_t *item = cbor_load(buf, len, &result); 1471bb154e3eSDorjoy Chowdhury if (!item || result.error.code != CBOR_ERR_NONE) { 1472bb154e3eSDorjoy Chowdhury goto cleanup; 1473bb154e3eSDorjoy Chowdhury } 1474bb154e3eSDorjoy Chowdhury 1475bb154e3eSDorjoy Chowdhury if (cbor_isa_string(item)) { 1476bb154e3eSDorjoy Chowdhury size = cbor_string_length(item); 1477bb154e3eSDorjoy Chowdhury req = cbor_string_handle(item); 1478bb154e3eSDorjoy Chowdhury root_type = CBOR_ROOT_TYPE_STRING; 1479bb154e3eSDorjoy Chowdhury } else if (cbor_isa_map(item) && cbor_map_size(item) == 1) { 1480bb154e3eSDorjoy Chowdhury struct cbor_pair *handle = cbor_map_handle(item); 1481bb154e3eSDorjoy Chowdhury if (cbor_isa_string(handle->key)) { 1482bb154e3eSDorjoy Chowdhury size = cbor_string_length(handle->key); 1483bb154e3eSDorjoy Chowdhury req = cbor_string_handle(handle->key); 1484bb154e3eSDorjoy Chowdhury root_type = CBOR_ROOT_TYPE_MAP; 1485bb154e3eSDorjoy Chowdhury } else { 1486bb154e3eSDorjoy Chowdhury goto cleanup; 1487bb154e3eSDorjoy Chowdhury } 1488bb154e3eSDorjoy Chowdhury } else { 1489bb154e3eSDorjoy Chowdhury goto cleanup; 1490bb154e3eSDorjoy Chowdhury } 1491bb154e3eSDorjoy Chowdhury 1492bb154e3eSDorjoy Chowdhury if (size == 0 || req == NULL) { 1493bb154e3eSDorjoy Chowdhury goto cleanup; 1494bb154e3eSDorjoy Chowdhury } 1495bb154e3eSDorjoy Chowdhury 1496bb154e3eSDorjoy Chowdhury for (int i = 0; i < ARRAY_SIZE(nsm_cmds); ++i) { 1497bb154e3eSDorjoy Chowdhury if (nsm_cmds[i].root_type == root_type && 1498bb154e3eSDorjoy Chowdhury strlen(nsm_cmds[i].name) == size && 1499bb154e3eSDorjoy Chowdhury memcmp(nsm_cmds[i].name, req, size) == 0) { 1500bb154e3eSDorjoy Chowdhury cbor_decref(&item); 1501bb154e3eSDorjoy Chowdhury return &nsm_cmds[i]; 1502bb154e3eSDorjoy Chowdhury } 1503bb154e3eSDorjoy Chowdhury } 1504bb154e3eSDorjoy Chowdhury 1505bb154e3eSDorjoy Chowdhury cleanup: 1506bb154e3eSDorjoy Chowdhury if (item) { 1507bb154e3eSDorjoy Chowdhury cbor_decref(&item); 1508bb154e3eSDorjoy Chowdhury } 1509bb154e3eSDorjoy Chowdhury return NULL; 1510bb154e3eSDorjoy Chowdhury } 1511bb154e3eSDorjoy Chowdhury 1512bb154e3eSDorjoy Chowdhury static bool get_nsm_request_response(VirtIONSM *vnsm, struct iovec *req, 1513bb154e3eSDorjoy Chowdhury struct iovec *resp, Error **errp) 1514bb154e3eSDorjoy Chowdhury { 1515bb154e3eSDorjoy Chowdhury const struct nsm_cmd *cmd; 1516bb154e3eSDorjoy Chowdhury 1517bb154e3eSDorjoy Chowdhury if (req->iov_len > NSM_REQUEST_MAX_SIZE) { 1518bb154e3eSDorjoy Chowdhury if (error_response(resp, NSM_INPUT_TOO_LARGE, errp)) { 1519bb154e3eSDorjoy Chowdhury return true; 1520bb154e3eSDorjoy Chowdhury } 1521bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize InputTooLarge response"); 1522bb154e3eSDorjoy Chowdhury return false; 1523bb154e3eSDorjoy Chowdhury } 1524bb154e3eSDorjoy Chowdhury 1525bb154e3eSDorjoy Chowdhury cmd = get_nsm_request_cmd(req->iov_base, req->iov_len); 1526bb154e3eSDorjoy Chowdhury 1527bb154e3eSDorjoy Chowdhury if (cmd == NULL) { 1528bb154e3eSDorjoy Chowdhury if (error_response(resp, NSM_INVALID_OPERATION, errp)) { 1529bb154e3eSDorjoy Chowdhury return true; 1530bb154e3eSDorjoy Chowdhury } 1531bb154e3eSDorjoy Chowdhury error_setg(errp, "Failed to initialize InvalidOperation response"); 1532bb154e3eSDorjoy Chowdhury return false; 1533bb154e3eSDorjoy Chowdhury } 1534bb154e3eSDorjoy Chowdhury 1535bb154e3eSDorjoy Chowdhury return cmd->response_fn(vnsm, req, resp, errp); 1536bb154e3eSDorjoy Chowdhury } 1537bb154e3eSDorjoy Chowdhury 1538bb154e3eSDorjoy Chowdhury static void handle_input(VirtIODevice *vdev, VirtQueue *vq) 1539bb154e3eSDorjoy Chowdhury { 1540bb154e3eSDorjoy Chowdhury g_autofree VirtQueueElement *out_elem = NULL; 1541bb154e3eSDorjoy Chowdhury g_autofree VirtQueueElement *in_elem = NULL; 1542bb154e3eSDorjoy Chowdhury VirtIONSM *vnsm = VIRTIO_NSM(vdev); 1543bb154e3eSDorjoy Chowdhury Error *err = NULL; 1544bb154e3eSDorjoy Chowdhury size_t sz; 1545bb154e3eSDorjoy Chowdhury struct iovec req = {.iov_base = NULL, .iov_len = 0}; 1546bb154e3eSDorjoy Chowdhury struct iovec res = {.iov_base = NULL, .iov_len = 0}; 1547bb154e3eSDorjoy Chowdhury 1548bb154e3eSDorjoy Chowdhury out_elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 1549bb154e3eSDorjoy Chowdhury if (!out_elem) { 1550bb154e3eSDorjoy Chowdhury /* nothing in virtqueue */ 1551bb154e3eSDorjoy Chowdhury return; 1552bb154e3eSDorjoy Chowdhury } 1553bb154e3eSDorjoy Chowdhury 1554bb154e3eSDorjoy Chowdhury sz = iov_size(out_elem->out_sg, out_elem->out_num); 1555bb154e3eSDorjoy Chowdhury if (sz == 0) { 1556bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Expected non-zero sized request buffer in " 1557bb154e3eSDorjoy Chowdhury "virtqueue"); 1558bb154e3eSDorjoy Chowdhury goto cleanup; 1559bb154e3eSDorjoy Chowdhury } 1560bb154e3eSDorjoy Chowdhury 1561bb154e3eSDorjoy Chowdhury in_elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 1562bb154e3eSDorjoy Chowdhury if (!in_elem) { 1563bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Expected response buffer after request buffer " 1564bb154e3eSDorjoy Chowdhury "in virtqueue"); 1565bb154e3eSDorjoy Chowdhury goto cleanup; 1566bb154e3eSDorjoy Chowdhury } 1567bb154e3eSDorjoy Chowdhury if (iov_size(in_elem->in_sg, in_elem->in_num) != NSM_RESPONSE_BUF_SIZE) { 1568bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Expected response buffer of length 0x3000"); 1569bb154e3eSDorjoy Chowdhury goto cleanup; 1570bb154e3eSDorjoy Chowdhury } 1571bb154e3eSDorjoy Chowdhury 1572bb154e3eSDorjoy Chowdhury req.iov_base = g_malloc(sz); 1573bb154e3eSDorjoy Chowdhury req.iov_len = iov_to_buf(out_elem->out_sg, out_elem->out_num, 0, 1574bb154e3eSDorjoy Chowdhury req.iov_base, sz); 1575bb154e3eSDorjoy Chowdhury if (req.iov_len != sz) { 1576bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Failed to copy request buffer"); 1577bb154e3eSDorjoy Chowdhury goto cleanup; 1578bb154e3eSDorjoy Chowdhury } 1579bb154e3eSDorjoy Chowdhury 1580bb154e3eSDorjoy Chowdhury res.iov_base = g_malloc(NSM_RESPONSE_BUF_SIZE); 1581bb154e3eSDorjoy Chowdhury res.iov_len = NSM_RESPONSE_BUF_SIZE; 1582bb154e3eSDorjoy Chowdhury 1583bb154e3eSDorjoy Chowdhury if (!get_nsm_request_response(vnsm, &req, &res, &err)) { 1584bb154e3eSDorjoy Chowdhury error_report_err(err); 1585bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Failed to get NSM request response"); 1586bb154e3eSDorjoy Chowdhury goto cleanup; 1587bb154e3eSDorjoy Chowdhury } 1588bb154e3eSDorjoy Chowdhury 1589bb154e3eSDorjoy Chowdhury sz = iov_from_buf(in_elem->in_sg, in_elem->in_num, 0, res.iov_base, 1590bb154e3eSDorjoy Chowdhury res.iov_len); 1591bb154e3eSDorjoy Chowdhury if (sz != res.iov_len) { 1592bb154e3eSDorjoy Chowdhury virtio_error(vdev, "Failed to copy response buffer"); 1593bb154e3eSDorjoy Chowdhury goto cleanup; 1594bb154e3eSDorjoy Chowdhury } 1595bb154e3eSDorjoy Chowdhury 1596bb154e3eSDorjoy Chowdhury g_free(req.iov_base); 1597bb154e3eSDorjoy Chowdhury g_free(res.iov_base); 1598bb154e3eSDorjoy Chowdhury virtqueue_push(vq, out_elem, 0); 1599131fe64eSAlexander Graf virtqueue_push(vq, in_elem, sz); 1600bb154e3eSDorjoy Chowdhury virtio_notify(vdev, vq); 1601bb154e3eSDorjoy Chowdhury return; 1602bb154e3eSDorjoy Chowdhury 1603bb154e3eSDorjoy Chowdhury cleanup: 1604bb154e3eSDorjoy Chowdhury g_free(req.iov_base); 1605bb154e3eSDorjoy Chowdhury g_free(res.iov_base); 1606bb154e3eSDorjoy Chowdhury if (out_elem) { 1607bb154e3eSDorjoy Chowdhury virtqueue_detach_element(vq, out_elem, 0); 1608bb154e3eSDorjoy Chowdhury } 1609bb154e3eSDorjoy Chowdhury if (in_elem) { 1610bb154e3eSDorjoy Chowdhury virtqueue_detach_element(vq, in_elem, 0); 1611bb154e3eSDorjoy Chowdhury } 1612bb154e3eSDorjoy Chowdhury } 1613bb154e3eSDorjoy Chowdhury 1614bb154e3eSDorjoy Chowdhury static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp) 1615bb154e3eSDorjoy Chowdhury { 1616bb154e3eSDorjoy Chowdhury return f; 1617bb154e3eSDorjoy Chowdhury } 1618bb154e3eSDorjoy Chowdhury 1619bb154e3eSDorjoy Chowdhury static bool extend_pcr(VirtIONSM *vnsm, int ind, uint8_t *data, uint16_t len) 1620bb154e3eSDorjoy Chowdhury { 1621bb154e3eSDorjoy Chowdhury Error *err = NULL; 1622bb154e3eSDorjoy Chowdhury struct PCRInfo *pcr = &(vnsm->pcrs[ind]); 1623bb154e3eSDorjoy Chowdhury size_t digest_len = QCRYPTO_HASH_DIGEST_LEN_SHA384; 1624bb154e3eSDorjoy Chowdhury uint8_t result[QCRYPTO_HASH_DIGEST_LEN_SHA384]; 1625bb154e3eSDorjoy Chowdhury uint8_t *ptr = result; 1626bb154e3eSDorjoy Chowdhury struct iovec iov[2] = { 1627bb154e3eSDorjoy Chowdhury { .iov_base = pcr->data, .iov_len = QCRYPTO_HASH_DIGEST_LEN_SHA384 }, 1628bb154e3eSDorjoy Chowdhury { .iov_base = data, .iov_len = len }, 1629bb154e3eSDorjoy Chowdhury }; 1630bb154e3eSDorjoy Chowdhury 1631bb154e3eSDorjoy Chowdhury if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA384, iov, 2, &ptr, &digest_len, 1632bb154e3eSDorjoy Chowdhury &err) < 0) { 1633bb154e3eSDorjoy Chowdhury return false; 1634bb154e3eSDorjoy Chowdhury } 1635bb154e3eSDorjoy Chowdhury 1636bb154e3eSDorjoy Chowdhury memcpy(pcr->data, result, QCRYPTO_HASH_DIGEST_LEN_SHA384); 1637bb154e3eSDorjoy Chowdhury return true; 1638bb154e3eSDorjoy Chowdhury } 1639bb154e3eSDorjoy Chowdhury 1640bb154e3eSDorjoy Chowdhury static void lock_pcr(VirtIONSM *vnsm, int ind) 1641bb154e3eSDorjoy Chowdhury { 1642bb154e3eSDorjoy Chowdhury vnsm->pcrs[ind].locked = true; 1643bb154e3eSDorjoy Chowdhury } 1644bb154e3eSDorjoy Chowdhury 1645bb154e3eSDorjoy Chowdhury static void virtio_nsm_device_realize(DeviceState *dev, Error **errp) 1646bb154e3eSDorjoy Chowdhury { 1647bb154e3eSDorjoy Chowdhury VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1648bb154e3eSDorjoy Chowdhury VirtIONSM *vnsm = VIRTIO_NSM(dev); 1649bb154e3eSDorjoy Chowdhury 1650bb154e3eSDorjoy Chowdhury vnsm->max_pcrs = NSM_MAX_PCRS; 1651bb154e3eSDorjoy Chowdhury vnsm->digest = (char *) "SHA384"; 1652bb154e3eSDorjoy Chowdhury if (vnsm->module_id == NULL) { 1653bb154e3eSDorjoy Chowdhury vnsm->module_id = (char *) "i-234-enc5678"; 1654bb154e3eSDorjoy Chowdhury } 1655bb154e3eSDorjoy Chowdhury vnsm->version_major = 1; 1656bb154e3eSDorjoy Chowdhury vnsm->version_minor = 0; 1657bb154e3eSDorjoy Chowdhury vnsm->version_patch = 0; 1658bb154e3eSDorjoy Chowdhury vnsm->extend_pcr = extend_pcr; 1659bb154e3eSDorjoy Chowdhury vnsm->lock_pcr = lock_pcr; 1660bb154e3eSDorjoy Chowdhury 1661bb154e3eSDorjoy Chowdhury virtio_init(vdev, VIRTIO_ID_NITRO_SEC_MOD, 0); 1662bb154e3eSDorjoy Chowdhury 1663bb154e3eSDorjoy Chowdhury vnsm->vq = virtio_add_queue(vdev, 2, handle_input); 1664bb154e3eSDorjoy Chowdhury } 1665bb154e3eSDorjoy Chowdhury 1666bb154e3eSDorjoy Chowdhury static void virtio_nsm_device_unrealize(DeviceState *dev) 1667bb154e3eSDorjoy Chowdhury { 1668bb154e3eSDorjoy Chowdhury VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1669bb154e3eSDorjoy Chowdhury 1670bb154e3eSDorjoy Chowdhury virtio_del_queue(vdev, 0); 1671bb154e3eSDorjoy Chowdhury virtio_cleanup(vdev); 1672bb154e3eSDorjoy Chowdhury } 1673bb154e3eSDorjoy Chowdhury 1674bb154e3eSDorjoy Chowdhury static const VMStateDescription vmstate_pcr_info_entry = { 1675bb154e3eSDorjoy Chowdhury .name = "pcr_info_entry", 1676bb154e3eSDorjoy Chowdhury .minimum_version_id = 1, 1677bb154e3eSDorjoy Chowdhury .version_id = 1, 1678bb154e3eSDorjoy Chowdhury .fields = (const VMStateField[]) { 1679bb154e3eSDorjoy Chowdhury VMSTATE_BOOL(locked, struct PCRInfo), 1680bb154e3eSDorjoy Chowdhury VMSTATE_UINT8_ARRAY(data, struct PCRInfo, 1681bb154e3eSDorjoy Chowdhury QCRYPTO_HASH_DIGEST_LEN_SHA384), 1682bb154e3eSDorjoy Chowdhury VMSTATE_END_OF_LIST() 1683bb154e3eSDorjoy Chowdhury }, 1684bb154e3eSDorjoy Chowdhury }; 1685bb154e3eSDorjoy Chowdhury 1686bb154e3eSDorjoy Chowdhury static const VMStateDescription vmstate_virtio_nsm_device = { 1687bb154e3eSDorjoy Chowdhury .name = "virtio-nsm-device", 1688bb154e3eSDorjoy Chowdhury .minimum_version_id = 1, 1689bb154e3eSDorjoy Chowdhury .version_id = 1, 1690bb154e3eSDorjoy Chowdhury .fields = (const VMStateField[]) { 1691bb154e3eSDorjoy Chowdhury VMSTATE_STRUCT_ARRAY(pcrs, VirtIONSM, NSM_MAX_PCRS, 1, 1692bb154e3eSDorjoy Chowdhury vmstate_pcr_info_entry, struct PCRInfo), 1693bb154e3eSDorjoy Chowdhury VMSTATE_END_OF_LIST() 1694bb154e3eSDorjoy Chowdhury }, 1695bb154e3eSDorjoy Chowdhury }; 1696bb154e3eSDorjoy Chowdhury 1697bb154e3eSDorjoy Chowdhury static const VMStateDescription vmstate_virtio_nsm = { 1698bb154e3eSDorjoy Chowdhury .name = "virtio-nsm", 1699bb154e3eSDorjoy Chowdhury .minimum_version_id = 1, 1700bb154e3eSDorjoy Chowdhury .version_id = 1, 1701bb154e3eSDorjoy Chowdhury .fields = (const VMStateField[]) { 1702bb154e3eSDorjoy Chowdhury VMSTATE_VIRTIO_DEVICE, 1703bb154e3eSDorjoy Chowdhury VMSTATE_END_OF_LIST() 1704bb154e3eSDorjoy Chowdhury }, 1705bb154e3eSDorjoy Chowdhury }; 1706bb154e3eSDorjoy Chowdhury 17071577a918SRichard Henderson static const Property virtio_nsm_properties[] = { 1708bb154e3eSDorjoy Chowdhury DEFINE_PROP_STRING("module-id", VirtIONSM, module_id), 1709bb154e3eSDorjoy Chowdhury }; 1710bb154e3eSDorjoy Chowdhury 1711*12d1a768SPhilippe Mathieu-Daudé static void virtio_nsm_class_init(ObjectClass *klass, const void *data) 1712bb154e3eSDorjoy Chowdhury { 1713bb154e3eSDorjoy Chowdhury DeviceClass *dc = DEVICE_CLASS(klass); 1714bb154e3eSDorjoy Chowdhury VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1715bb154e3eSDorjoy Chowdhury 1716bb154e3eSDorjoy Chowdhury device_class_set_props(dc, virtio_nsm_properties); 1717bb154e3eSDorjoy Chowdhury dc->vmsd = &vmstate_virtio_nsm; 1718bb154e3eSDorjoy Chowdhury set_bit(DEVICE_CATEGORY_MISC, dc->categories); 1719bb154e3eSDorjoy Chowdhury vdc->realize = virtio_nsm_device_realize; 1720bb154e3eSDorjoy Chowdhury vdc->unrealize = virtio_nsm_device_unrealize; 1721bb154e3eSDorjoy Chowdhury vdc->get_features = get_features; 1722bb154e3eSDorjoy Chowdhury vdc->vmsd = &vmstate_virtio_nsm_device; 1723bb154e3eSDorjoy Chowdhury } 1724bb154e3eSDorjoy Chowdhury 1725bb154e3eSDorjoy Chowdhury static const TypeInfo virtio_nsm_info = { 1726bb154e3eSDorjoy Chowdhury .name = TYPE_VIRTIO_NSM, 1727bb154e3eSDorjoy Chowdhury .parent = TYPE_VIRTIO_DEVICE, 1728bb154e3eSDorjoy Chowdhury .instance_size = sizeof(VirtIONSM), 1729bb154e3eSDorjoy Chowdhury .class_init = virtio_nsm_class_init, 1730bb154e3eSDorjoy Chowdhury }; 1731bb154e3eSDorjoy Chowdhury 1732bb154e3eSDorjoy Chowdhury static void virtio_register_types(void) 1733bb154e3eSDorjoy Chowdhury { 1734bb154e3eSDorjoy Chowdhury type_register_static(&virtio_nsm_info); 1735bb154e3eSDorjoy Chowdhury } 1736bb154e3eSDorjoy Chowdhury 1737bb154e3eSDorjoy Chowdhury type_init(virtio_register_types) 1738