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