1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2017, Intel Corporation
4 * All rights reserved.
5 */
6 #include <inttypes.h>
7 #include <stdint.h>
8 #include <string.h>
9
10 #include <tss2/tss2_tpm2_types.h>
11 #include <tss2/tss2_mu.h>
12
13 #include "tpm2-command.h"
14 #include "tpm2-header.h"
15 #include "util.h"
16 /* macros to make getting at fields in the command more simple */
17
18 #define HANDLE_AREA_OFFSET TPM_HEADER_SIZE
19 #define HANDLE_OFFSET(i) (HANDLE_AREA_OFFSET + sizeof (TPM2_HANDLE) * i)
20 #define HANDLE_END_OFFSET(i) (HANDLE_OFFSET (i) + sizeof (TPM2_HANDLE))
21 #define HANDLE_GET(buffer, count) \
22 (*(TPM2_HANDLE*)(&buffer [HANDLE_OFFSET (count)]))
23 /*
24 * Offset of capability field in TPM2_GetCapability command buffer is
25 * immediately after the header.
26 */
27 #define CAP_OFFSET TPM_HEADER_SIZE
28 #define CAP_END_OFFSET (CAP_OFFSET + sizeof (TPM2_CAP))
29 #define CAP_GET(buffer) (*(TPM2_CAP*)(&buffer [CAP_OFFSET]))
30 /*
31 * Offset of property field in TPM2_GetCapability command buffer is
32 * immediately after the capability field.
33 */
34 #define PROPERTY_OFFSET CAP_END_OFFSET
35 #define PROPERTY_END_OFFSET (PROPERTY_OFFSET + sizeof (UINT32))
36 #define PROPERTY_GET(buffer) (*(UINT32*)(&buffer [PROPERTY_OFFSET]))
37 /*
38 * The offset of the property count field is immediately following the
39 * property field.
40 */
41 #define PROPERTY_COUNT_OFFSET PROPERTY_END_OFFSET
42 #define PROPERTY_COUNT_END_OFFSET (PROPERTY_COUNT_OFFSET + sizeof (UINT32))
43 #define PROPERTY_COUNT_GET(buffer) (*(UINT32*)(&buffer [PROPERTY_COUNT_OFFSET]))
44 /*
45 * Helper macros to aid in the access of various parts of the command
46 * authorization area.
47 */
48 #define AUTH_AREA_OFFSET(cmd) \
49 (TPM_HEADER_SIZE + (tpm2_command_get_handle_count (cmd) * sizeof (TPM2_HANDLE)))
50 #define AUTH_AREA_SIZE_OFFSET(cmd) AUTH_AREA_OFFSET (cmd)
51 #define AUTH_AREA_SIZE_END_OFFSET(cmd) \
52 (AUTH_AREA_SIZE_OFFSET (cmd) + sizeof (UINT32))
53 #define AUTH_AREA_GET_SIZE(cmd) \
54 (be32toh (*(UINT32*)(&cmd->buffer [AUTH_AREA_SIZE_OFFSET (cmd)])))
55 #define AUTH_AREA_FIRST_OFFSET(cmd) (AUTH_AREA_SIZE_END_OFFSET (cmd))
56 #define AUTH_AREA_END_OFFSET(cmd) \
57 (AUTH_AREA_FIRST_OFFSET (cmd) + AUTH_AREA_GET_SIZE (cmd))
58 /*
59 * Helper macros to aid in accessing parts of a session authorization. These
60 * are the individual authorizations in the authorization area of the command.
61 * The 'cmd' parameter must be a reference to a valid Tpm2Command object.
62 * The 'index' parameter must be the index into the Tpm2Command buffer where
63 * the authorization we wish to query resides.
64 */
65 #define AUTH_HANDLE_OFFSET(index) (index + 0)
66 #define AUTH_HANDLE_END_OFFSET(index) \
67 (AUTH_HANDLE_OFFSET(index) + sizeof (TPM2_HANDLE))
68 #define AUTH_GET_HANDLE(cmd, index) \
69 (be32toh (*(TPM2_HANDLE*)&cmd->buffer [AUTH_HANDLE_OFFSET (index)]))
70 /* nonce */
71 #define AUTH_NONCE_SIZE_OFFSET(index) (AUTH_HANDLE_END_OFFSET (index))
72 #define AUTH_NONCE_SIZE_END_OFFSET(index) \
73 (AUTH_NONCE_SIZE_OFFSET(index) + sizeof (UINT16))
74 #define AUTH_GET_NONCE_SIZE(cmd, index) \
75 (be16toh (*(UINT16*)&cmd->buffer [AUTH_NONCE_SIZE_OFFSET (index)]))
76 #define AUTH_NONCE_BUF_OFFSET(index) \
77 (AUTH_NONCE_SIZE_END_OFFSET (index))
78 #define AUTH_NONCE_BUF_END_OFFSET(cmd, index) \
79 (AUTH_NONCE_BUF_OFFSET (index) + AUTH_GET_NONCE_SIZE (cmd, index))
80 /* session attributes */
81 #define AUTH_SESSION_ATTRS_OFFSET(cmd, index) \
82 (AUTH_NONCE_BUF_END_OFFSET (cmd, index))
83 /*
84 * in AUTH_SESSION_ATTRS_END_OFFSET the UINT8 should be TPMA_SESSION but the
85 * TSS headers got this wrong
86 */
87 #define AUTH_SESSION_ATTRS_END_OFFSET(cmd, index) \
88 (AUTH_SESSION_ATTRS_OFFSET (cmd, index) + sizeof (UINT8))
89 #define AUTH_GET_SESSION_ATTRS(cmd, index) \
90 ((TPMA_SESSION)(UINT8)cmd->buffer [AUTH_SESSION_ATTRS_OFFSET (cmd, index)])
91 /* authorization */
92 #define AUTH_AUTH_SIZE_OFFSET(cmd, index) \
93 (AUTH_SESSION_ATTRS_END_OFFSET (cmd, index))
94 #define AUTH_AUTH_SIZE_END_OFFSET(cmd, index) \
95 (AUTH_AUTH_SIZE_OFFSET (cmd, index) + sizeof (UINT16))
96 #define AUTH_GET_AUTH_SIZE(cmd, index) \
97 (be16toh (*(UINT16*)&cmd->buffer [AUTH_AUTH_SIZE_OFFSET (cmd, index)]))
98 #define AUTH_AUTH_BUF_OFFSET(cmd, index) \
99 (AUTH_AUTH_SIZE_END_OFFSET (cmd, index))
100 #define AUTH_AUTH_BUF_END_OFFSET(cmd, index) \
101 (AUTH_AUTH_BUF_OFFSET(cmd, index) + AUTH_GET_AUTH_SIZE (cmd, index))
102
103 G_DEFINE_TYPE (Tpm2Command, tpm2_command, G_TYPE_OBJECT);
104
105 enum {
106 PROP_0,
107 PROP_ATTRIBUTES,
108 PROP_SESSION,
109 PROP_BUFFER,
110 PROP_BUFFER_SIZE,
111 N_PROPERTIES
112 };
113 static GParamSpec *obj_properties [N_PROPERTIES] = { NULL, };
114 /**
115 * GObject property setter.
116 */
117 static void
tpm2_command_set_property(GObject * object,guint property_id,GValue const * value,GParamSpec * pspec)118 tpm2_command_set_property (GObject *object,
119 guint property_id,
120 GValue const *value,
121 GParamSpec *pspec)
122 {
123 Tpm2Command *self = TPM2_COMMAND (object);
124
125 switch (property_id) {
126 case PROP_ATTRIBUTES:
127 self->attributes = (TPMA_CC)g_value_get_uint (value);
128 break;
129 case PROP_BUFFER:
130 if (self->buffer != NULL) {
131 g_warning (" buffer already set");
132 break;
133 }
134 self->buffer = (guint8*)g_value_get_pointer (value);
135 break;
136 case PROP_BUFFER_SIZE:
137 self->buffer_size = g_value_get_uint (value);
138 break;
139 case PROP_SESSION:
140 if (self->connection != NULL) {
141 g_warning (" connection already set");
142 break;
143 }
144 self->connection = g_value_get_object (value);
145 if (self->connection) {
146 g_object_ref (self->connection);
147 }
148 break;
149 default:
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
151 break;
152 }
153 }
154 /**
155 * GObject property getter.
156 */
157 static void
tpm2_command_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)158 tpm2_command_get_property (GObject *object,
159 guint property_id,
160 GValue *value,
161 GParamSpec *pspec)
162 {
163 Tpm2Command *self = TPM2_COMMAND (object);
164
165 switch (property_id) {
166 case PROP_ATTRIBUTES:
167 g_value_set_uint (value, self->attributes);
168 break;
169 case PROP_BUFFER:
170 g_value_set_pointer (value, self->buffer);
171 break;
172 case PROP_BUFFER_SIZE:
173 g_value_set_uint (value, self->buffer_size);
174 break;
175 case PROP_SESSION:
176 g_value_set_object (value, self->connection);
177 break;
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
180 break;
181 }
182 }
183 static void
tpm2_command_dispose(GObject * obj)184 tpm2_command_dispose (GObject *obj)
185 {
186 Tpm2Command *cmd = TPM2_COMMAND (obj);
187
188 g_clear_object (&cmd->connection);
189 G_OBJECT_CLASS (tpm2_command_parent_class)->dispose (obj);
190 }
191 /**
192 * override the parent finalize method so we can free the data associated with
193 * the DataMessage instance.
194 */
195 static void
tpm2_command_finalize(GObject * obj)196 tpm2_command_finalize (GObject *obj)
197 {
198 Tpm2Command *cmd = TPM2_COMMAND (obj);
199
200 g_debug ("tpm2_command_finalize");
201 g_clear_pointer (&cmd->buffer, g_free);
202 G_OBJECT_CLASS (tpm2_command_parent_class)->finalize (obj);
203 }
204 static void
tpm2_command_init(Tpm2Command * command)205 tpm2_command_init (Tpm2Command *command)
206 {
207 UNUSED_PARAM(command);
208 /* noop */
209 }
210 /**
211 * Boilerplate GObject initialization. Get a pointer to the parent class,
212 * setup a finalize function.
213 */
214 static void
tpm2_command_class_init(Tpm2CommandClass * klass)215 tpm2_command_class_init (Tpm2CommandClass *klass)
216 {
217 GObjectClass *object_class = G_OBJECT_CLASS (klass);
218
219 if (tpm2_command_parent_class == NULL)
220 tpm2_command_parent_class = g_type_class_peek_parent (klass);
221 object_class->dispose = tpm2_command_dispose;
222 object_class->finalize = tpm2_command_finalize;
223 object_class->get_property = tpm2_command_get_property;
224 object_class->set_property = tpm2_command_set_property;
225
226 obj_properties [PROP_ATTRIBUTES] =
227 g_param_spec_uint ("attributes",
228 "TPMA_CC",
229 "Attributes for command.",
230 0,
231 UINT32_MAX,
232 0,
233 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
234 obj_properties [PROP_BUFFER] =
235 g_param_spec_pointer ("buffer",
236 "TPM2 command buffer",
237 "memory buffer holding a TPM2 command",
238 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
239 obj_properties [PROP_BUFFER_SIZE] =
240 g_param_spec_uint ("buffer-size",
241 "sizeof command buffer",
242 "size of buffer holding the TPM2 command",
243 0,
244 UTIL_BUF_MAX,
245 0,
246 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
247 obj_properties [PROP_SESSION] =
248 g_param_spec_object ("connection",
249 "Session object",
250 "The Connection object that sent the command",
251 TYPE_CONNECTION,
252 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
253 g_object_class_install_properties (object_class,
254 N_PROPERTIES,
255 obj_properties);
256 }
257 /**
258 * Boilerplate constructor, but some GObject properties would be nice.
259 */
260 Tpm2Command*
tpm2_command_new(Connection * connection,guint8 * buffer,size_t size,TPMA_CC attributes)261 tpm2_command_new (Connection *connection,
262 guint8 *buffer,
263 size_t size,
264 TPMA_CC attributes)
265 {
266 return TPM2_COMMAND (g_object_new (TYPE_TPM2_COMMAND,
267 "attributes", attributes,
268 "buffer", buffer,
269 "buffer-size", size,
270 "connection", connection,
271 NULL));
272 }
273 #define CONTEXT_SAVE_CMD_SIZE (TPM_HEADER_SIZE + sizeof (TPM2_HANDLE))
274 Tpm2Command*
tpm2_command_new_context_save(TPM2_HANDLE handle)275 tpm2_command_new_context_save (TPM2_HANDLE handle)
276 {
277 TSS2_RC rc;
278 uint8_t *buf = g_malloc0 (CONTEXT_SAVE_CMD_SIZE);
279 size_t offset = TPM_HEADER_SIZE;
280
281 rc = tpm2_header_init (buf,
282 CONTEXT_SAVE_CMD_SIZE,
283 TPM2_ST_NO_SESSIONS,
284 CONTEXT_SAVE_CMD_SIZE,
285 TPM2_CC_ContextSave);
286 if (rc != TSS2_RC_SUCCESS) {
287 goto err_out;
288 }
289 rc = Tss2_MU_TPM2_HANDLE_Marshal (handle,
290 buf,
291 CONTEXT_SAVE_CMD_SIZE,
292 &offset);
293 if (rc != TSS2_RC_SUCCESS) {
294 goto err_out;
295 }
296 /* TPMA_CC here is hard coded to the appropriate value for ContextSave */
297 return tpm2_command_new (NULL, buf, CONTEXT_SAVE_CMD_SIZE, 0x02000162);
298
299 err_out:
300 g_warning ("%s: failed", __func__);
301 g_free (buf);
302 return NULL;
303 }
304 Tpm2Command*
tpm2_command_new_context_load(uint8_t * buf,size_t size)305 tpm2_command_new_context_load (uint8_t *buf,
306 size_t size)
307 {
308 TSS2_RC rc;
309 UINT32 size_new = TPM_HEADER_SIZE + size;
310 uint8_t *buf_tmp = g_malloc0 (size_new);
311
312 rc = tpm2_header_init (buf_tmp,
313 size_new,
314 TPM2_ST_NO_SESSIONS,
315 size_new,
316 TPM2_CC_ContextLoad);
317 if (rc != TSS2_RC_SUCCESS) {
318 g_free (buf_tmp);
319 return NULL;
320 }
321 memcpy (&buf_tmp [TPM_HEADER_SIZE], buf, size);
322 /* TPMA_CC here is hard coded to the appropriate value for ContextLoad */
323 return tpm2_command_new (NULL, buf_tmp, size_new, 0x10000161);
324 }
325 /* Simple "getter" to expose the attributes associated with the command. */
326 TPMA_CC
tpm2_command_get_attributes(Tpm2Command * command)327 tpm2_command_get_attributes (Tpm2Command *command)
328 {
329 return command->attributes;
330 }
331 /**
332 */
333 guint8*
tpm2_command_get_buffer(Tpm2Command * command)334 tpm2_command_get_buffer (Tpm2Command *command)
335 {
336 return command->buffer;
337 }
338 /**
339 */
340 TPM2_CC
tpm2_command_get_code(Tpm2Command * command)341 tpm2_command_get_code (Tpm2Command *command)
342 {
343 return get_command_code (command->buffer);
344 }
345 /**
346 */
347 guint32
tpm2_command_get_size(Tpm2Command * command)348 tpm2_command_get_size (Tpm2Command *command)
349 {
350 return get_command_size (command->buffer);
351 }
352 /**
353 */
354 TPMI_ST_COMMAND_TAG
tpm2_command_get_tag(Tpm2Command * command)355 tpm2_command_get_tag (Tpm2Command *command)
356 {
357 return get_command_tag (command->buffer);
358 }
359 /*
360 * Return the Connection object associated with this Tpm2Command. This
361 * is the Connection object representing the client that sent this command.
362 * The reference count on this object is incremented before the Connection
363 * object is returned to the caller. The caller is responsible for
364 * decrementing the reference count when it is done using the connection object.
365 */
366 Connection*
tpm2_command_get_connection(Tpm2Command * command)367 tpm2_command_get_connection (Tpm2Command *command)
368 {
369 if (command->connection) {
370 g_object_ref (command->connection);
371 }
372 return command->connection;
373 }
374 /* Return the number of handles in the command. */
375 guint8
tpm2_command_get_handle_count(Tpm2Command * command)376 tpm2_command_get_handle_count (Tpm2Command *command)
377 {
378 g_debug ("tpm2_command_get_handle_count");
379 uint32_t tmp;
380
381 if (command == NULL) {
382 g_warning ("tpm2_command_get_handle_count received NULL parameter");
383 return 0;
384 }
385 tmp = tpm2_command_get_attributes (command);
386 return (guint8)((tmp & TPMA_CC_CHANDLES_MASK) >> TPMA_CC_CHANDLES_SHIFT);
387 }
388 /*
389 * Simple function to access handles in the provided Tpm2Command. The
390 * 'handle_number' parameter is a 0-based index into the handle area
391 * which is effectively an array. If the handle_number requests a handle
392 * beyond the end of this array 0 is returned.
393 */
394 TPM2_HANDLE
tpm2_command_get_handle(Tpm2Command * command,guint8 handle_number)395 tpm2_command_get_handle (Tpm2Command *command,
396 guint8 handle_number)
397 {
398 guint8 real_count;
399 size_t end;
400
401 if (command == NULL)
402 return 0;
403 real_count = tpm2_command_get_handle_count (command);
404 end = HANDLE_END_OFFSET (handle_number);
405 if (real_count > handle_number && end <= command->buffer_size) {
406 return be32toh (HANDLE_GET (command->buffer, handle_number));
407 } else {
408 return 0;
409 }
410 }
411 /*
412 * Simple function to set a handle at the 0-based index into the Tpm2Command
413 * handle area to the provided value. If the handle_number is past the bounds
414 * FALSE is returned.
415 */
416 gboolean
tpm2_command_set_handle(Tpm2Command * command,TPM2_HANDLE handle,guint8 handle_number)417 tpm2_command_set_handle (Tpm2Command *command,
418 TPM2_HANDLE handle,
419 guint8 handle_number)
420 {
421 guint8 real_count;
422 size_t end;
423
424 if (command == NULL)
425 return FALSE;
426 real_count = tpm2_command_get_handle_count (command);
427 end = HANDLE_END_OFFSET (handle_number);
428 if (real_count > handle_number && end <= command->buffer_size) {
429 HANDLE_GET (command->buffer, handle_number) = htobe32 (handle);
430 return TRUE;
431 } else {
432 return FALSE;
433 }
434 }
435 /*
436 * Return the handles from the Tpm2Command back to the caller by way of the
437 * handles parameter. The caller must allocate sufficient space to hold
438 * however many handles are in this command. Take a look @
439 * tpm2_command_get_handle_count.
440 */
441 gboolean
tpm2_command_get_handles(Tpm2Command * command,TPM2_HANDLE handles[],size_t * count)442 tpm2_command_get_handles (Tpm2Command *command,
443 TPM2_HANDLE handles[],
444 size_t *count)
445 {
446 guint8 real_count;
447 size_t i;
448
449 if (command == NULL || handles == NULL || count == NULL) {
450 g_warning ("tpm2_command_get_handles passed NULL parameter");
451 return FALSE;
452 }
453 real_count = tpm2_command_get_handle_count (command);
454 if (real_count > *count) {
455 g_warning ("tpm2_command_get_handles passed insufficient handle array");
456 return FALSE;
457 }
458
459 for (i = 0; i < real_count; ++i) {
460 handles[i] = tpm2_command_get_handle (command, i);
461
462 if (handles[i] == 0) {
463 /* no more handles could be extracted */
464 break;
465 }
466 }
467 *count = i;
468
469 return TRUE;
470 }
471 /*
472 * This function is a work around. The handle in a command buffer for the
473 * FlushContext command is not in the handle area and no handles are reported
474 * in the attributes structure. This means that in order to cope with
475 * virtualized handles in this command we must reach into the parameter area
476 * which breaks the abstractions we've built for accessing handles. Thus we
477 * provide a special function for getting at this single handle.
478 * Use this function with caution.
479 */
480 TSS2_RC
tpm2_command_get_flush_handle(Tpm2Command * command,TPM2_HANDLE * handle)481 tpm2_command_get_flush_handle (Tpm2Command *command,
482 TPM2_HANDLE *handle)
483 {
484 if (command == NULL || handle == NULL) {
485 g_error ("tpm2_command_get_flush_handle passed null parameter");
486 }
487 if (tpm2_command_get_code (command) != TPM2_CC_FlushContext) {
488 g_warning ("tpm2_command_get_flush_handle called with wrong command");
489 *handle = 0;
490 return RM_RC (TPM2_RC_TYPE);
491 }
492 if (command->buffer_size < TPM_HEADER_SIZE + sizeof (TPM2_HANDLE)) {
493 g_warning ("%s: command buffer_size insufficient", __func__);
494 *handle = 0;
495 return RM_RC (TPM2_RC_INSUFFICIENT);
496 }
497 /*
498 * Despite not technically being in the "handle area" of the command we
499 * are still able to access the handle as though it were. This is because
500 * there are no other handles or authorizations allowed in the command and
501 * the handle being flushed is the first parameter.
502 */
503 *handle = be32toh (HANDLE_GET (tpm2_command_get_buffer (command), 0));
504 return TSS2_RC_SUCCESS;
505 }
506 /*
507 * When provided with a Tpm2Command that represents a call to the
508 * GetCapability command this function will extract the 'capability' field.
509 * On error 0 is returned.
510 */
511 TPM2_CAP
tpm2_command_get_cap(Tpm2Command * command)512 tpm2_command_get_cap (Tpm2Command *command)
513 {
514 if (command == NULL) {
515 g_warning ("tpm2_command_get_cap passed NULL parameter");
516 return 0;
517 }
518 if (tpm2_command_get_code (command) != TPM2_CC_GetCapability) {
519 g_warning ("tpm2_command_get_cap provided a Tpm2Command buffer "
520 "containing the wrong command code.");
521 return 0;
522 }
523 if (command->buffer_size < CAP_END_OFFSET) {
524 g_warning ("%s insufficient buffer", __func__);
525 return 0;
526 }
527 return (TPM2_CAP)be32toh (CAP_GET (tpm2_command_get_buffer (command)));
528 }
529 /*
530 * When provided with a Tpm2Command that represents a call to the
531 * GetCapability command this function will extract the 'property' field.
532 * On error 0 is returned.
533 */
534 UINT32
tpm2_command_get_prop(Tpm2Command * command)535 tpm2_command_get_prop (Tpm2Command *command)
536 {
537 if (command == NULL) {
538 g_warning ("tpm2_command_get_prop passed NULL parameter");
539 return 0;
540 }
541 if (tpm2_command_get_code (command) != TPM2_CC_GetCapability) {
542 g_warning ("tpm2_command_get_cap provided a Tpm2Command buffer "
543 "containing the wrong command code.");
544 return 0;
545 }
546 if (command->buffer_size < PROPERTY_END_OFFSET) {
547 g_warning ("%s insufficient buffer", __func__);
548 return 0;
549 }
550 return (UINT32)be32toh (PROPERTY_GET (tpm2_command_get_buffer (command)));
551 }
552 /*
553 * When provided with a Tpm2Command that represents a call to the
554 * GetCapability command this function will extract the 'propertyCount' field.
555 * On error 0 is returned.
556 */
557 UINT32
tpm2_command_get_prop_count(Tpm2Command * command)558 tpm2_command_get_prop_count (Tpm2Command *command)
559 {
560 if (command == NULL) {
561 g_warning ("tpm2_command_get_prop_count passed NULL parameter");
562 return 0;
563 }
564 if (tpm2_command_get_code (command) != TPM2_CC_GetCapability) {
565 g_warning ("tpm2_command_get_cap provided a Tpm2Command buffer "
566 "containing the wrong command code.");
567 return 0;
568 }
569 if (command->buffer_size < PROPERTY_COUNT_END_OFFSET) {
570 g_warning ("%s insufficient buffer", __func__);
571 return 0;
572 }
573 return (UINT32)be32toh (PROPERTY_COUNT_GET (tpm2_command_get_buffer (command)));
574 }
575 /*
576 * This is a convenience function to keep from having to compare the tag
577 * value to TPM2_ST_(NO_)?_SESSIONS repeatedly.
578 */
579 gboolean
tpm2_command_has_auths(Tpm2Command * command)580 tpm2_command_has_auths (Tpm2Command *command)
581 {
582 if (command == NULL) {
583 g_warning ("tpm2_command_has_auths passed NULL parameter");
584 return FALSE;
585 }
586 if (tpm2_command_get_tag (command) == TPM2_ST_NO_SESSIONS) {
587 return FALSE;
588 } else {
589 return TRUE;
590 }
591 }
592 /*
593 * When provided with a Tpm2Command with auths in the auth area this function
594 * will return the total size of the auth area.
595 */
596 UINT32
tpm2_command_get_auths_size(Tpm2Command * command)597 tpm2_command_get_auths_size (Tpm2Command *command)
598 {
599 size_t auth_size_end;
600
601 if (command == NULL) {
602 g_warning ("tpm2_command_get_auths_size passed NULL parameter");
603 return 0;
604 }
605 if (!tpm2_command_has_auths (command)) {
606 g_warning ("%s: Tpm2Command has no auths", __func__);
607 return 0;
608 }
609 auth_size_end = AUTH_AREA_SIZE_END_OFFSET (command);
610 g_debug ("%s: auth_size_end: %zu", __func__, auth_size_end);
611 g_debug ("%s: buffer_size: %zu", __func__, command->buffer_size);
612 if (AUTH_AREA_SIZE_END_OFFSET (command) > command->buffer_size) {
613 g_warning ("%s reading size of auth area would overrun command buffer."
614 " Returning 0", __func__);
615 return 0;
616 }
617
618 return AUTH_AREA_GET_SIZE (command);
619 }
620 /*
621 * This function extracts the authorization handle from the entry in the
622 * auth area that begins at offset 'auth_offset'. Any failure to read this
623 * value will return 0.
624 */
625 TPM2_HANDLE
tpm2_command_get_auth_handle(Tpm2Command * command,size_t auth_index)626 tpm2_command_get_auth_handle (Tpm2Command *command,
627 size_t auth_index)
628 {
629 if (command == NULL) {
630 return 0;
631 }
632 if (AUTH_HANDLE_END_OFFSET (auth_index) > command->buffer_size) {
633 g_warning ("%s attempt to access authorization handle overruns "
634 " command buffer", __func__);
635 return 0;
636 }
637 return AUTH_GET_HANDLE (command, auth_index);
638 }
639 TPMA_SESSION
tpm2_command_get_auth_attrs(Tpm2Command * command,size_t auth_offset)640 tpm2_command_get_auth_attrs (Tpm2Command *command,
641 size_t auth_offset)
642 {
643 size_t attrs_end;
644
645 if (command == NULL) {
646 return (TPMA_SESSION)(UINT8)0;
647 }
648 attrs_end = AUTH_SESSION_ATTRS_END_OFFSET (command, auth_offset);
649 if (attrs_end > command->buffer_size) {
650 g_warning ("%s attempt to access session attributes overruns command "
651 "buffer", __func__);
652 return (TPMA_SESSION)(UINT8)0;
653 }
654 return AUTH_GET_SESSION_ATTRS (command, auth_offset);
655 }
656 /*
657 * The caller provided GFunc is invoked once for each authorization in the
658 * command authorization area. The first parameter passed to 'func' is a
659 * pointer to the start of the authorization data. The second parameter is
660 * the caller provided 'user_data'.
661 */
662 gboolean
tpm2_command_foreach_auth(Tpm2Command * command,GFunc callback,gpointer user_data)663 tpm2_command_foreach_auth (Tpm2Command *command,
664 GFunc callback,
665 gpointer user_data)
666 {
667 size_t offset;
668
669 if (command == NULL || callback == NULL) {
670 g_warning ("%s passed NULL parameter", __func__);
671 return FALSE;
672 }
673
674 if (AUTH_AREA_FIRST_OFFSET (command) > command->buffer_size) {
675 g_warning ("%s: auth area begins after end of buffer", __func__);
676 return FALSE;
677 }
678
679 if (AUTH_AREA_END_OFFSET (command) > command->buffer_size) {
680 g_warning ("%s: command buffer size insufficient to iterate all auths",
681 __func__);
682 return FALSE;
683 }
684
685 for (offset = AUTH_AREA_FIRST_OFFSET (command);
686 offset < AUTH_AREA_END_OFFSET (command);
687 offset = AUTH_AUTH_BUF_END_OFFSET (command, offset))
688 {
689 size_t offset_tmp = offset;
690 callback (&offset_tmp, user_data);
691 }
692
693 return TRUE;
694 }
695