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