diff mbox

[U-Boot,1/6] tpm: add AUTH1 cmds for LoadKey2 and GetPubKey

Message ID 1366628805-29964-2-git-send-email-eibach@gdsys.de
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Dirk Eibach April 22, 2013, 11:06 a.m. UTC
From: Reinhard Pfau <pfau@gdsys.de>

Extend the tpm library with support for single authorized (AUTH1) commands
as specified in the TCG Main Specification 1.2. (The internally used helper
functions are implemented in a way that they could also be used for double
authorized commands if someone needs it.)

Provide enums with the return codes from the TCG Main specification.

For now only a single OIAP session is supported.

OIAP authorized version of the commands TPM_LoadKey2 and TPM_GetPubKey are
provided. Both features are available using the 'tpm' command, too.

Authorized commands are enabled with CONFIG_TPM_AUTH_SESSIONS. (Note that
this also requires CONFIG_SHA1 to be enabled.)

Signed-off-by: Reinhard Pfau <pfau@gdsys.de>

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 README           |   14 +++
 common/cmd_tpm.c |   93 +++++++++++++++
 include/tpm.h    |  174 +++++++++++++++++++++++++++
 lib/tpm.c        |  348 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 628 insertions(+), 1 deletion(-)

Comments

Che-liang Chiou April 22, 2013, 5:51 p.m. UTC | #1
Acked-by: Che-Liang Chiou <clchiou@chromium.org>

On Mon, Apr 22, 2013 at 4:06 AM, Dirk Eibach <eibach@gdsys.de> wrote:
> From: Reinhard Pfau <pfau@gdsys.de>
>
> Extend the tpm library with support for single authorized (AUTH1) commands
> as specified in the TCG Main Specification 1.2. (The internally used helper
> functions are implemented in a way that they could also be used for double
> authorized commands if someone needs it.)
>
> Provide enums with the return codes from the TCG Main specification.
>
> For now only a single OIAP session is supported.
>
> OIAP authorized version of the commands TPM_LoadKey2 and TPM_GetPubKey are
> provided. Both features are available using the 'tpm' command, too.
>
> Authorized commands are enabled with CONFIG_TPM_AUTH_SESSIONS. (Note that
> this also requires CONFIG_SHA1 to be enabled.)
>
> Signed-off-by: Reinhard Pfau <pfau@gdsys.de>
>
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
>  README           |   14 +++
>  common/cmd_tpm.c |   93 +++++++++++++++
>  include/tpm.h    |  174 +++++++++++++++++++++++++++
>  lib/tpm.c        |  348 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 628 insertions(+), 1 deletion(-)
>
> diff --git a/README b/README
> index 0bc0af5..58b2ee5 100644
> --- a/README
> +++ b/README
> @@ -1210,6 +1210,20 @@ The following options need to be configured:
>                         to. Contemporary x86 systems usually map it at
>                         0xfed40000.
>
> +               CONFIG_CMD_TPM
> +               Add tpm monitor functions.
> +               Requires CONFIG_TPM. If CONFIG_TPM_AUTH_SESSIONS is set, also
> +               provides monitor access to authorized functions.
> +
> +               CONFIG_TPM
> +               Define this to enable the TPM support library which provides
> +               functional interfaces to some TPM commands.
> +               Requires support for a TPM device.
> +
> +               CONFIG_TPM_AUTH_SESSIONS
> +               Define this to enable authorized functions in the TPM library.
> +               Requires CONFIG_TPM and CONFIG_SHA1.
> +
>  - USB Support:
>                 At the moment only the UHCI host controller is
>                 supported (PIP405, MIP405, MPC5200); define
> diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c
> index 46fae18..c8767a4 100644
> --- a/common/cmd_tpm.c
> +++ b/common/cmd_tpm.c
> @@ -546,6 +546,72 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,
>         return convert_return_code(err);
>  }
>
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +
> +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       uint32_t auth_handle, err;
> +
> +       err = tpm_oiap(&auth_handle);
> +
> +       return convert_return_code(err);
> +}
> +
> +static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       uint32_t parent_handle, key_len, key_handle, err;
> +       uint8_t usage_auth[20];
> +       void *key;
> +
> +       if (argc < 5)
> +               return CMD_RET_USAGE;
> +
> +       parent_handle = simple_strtoul(argv[1], NULL, 0);
> +       key = (void *)simple_strtoul(argv[2], NULL, 0);
> +       key_len = simple_strtoul(argv[3], NULL, 0);
> +       if (strlen(argv[4]) != 40)
> +               return CMD_RET_FAILURE;
> +       parse_byte_string(argv[4], usage_auth, NULL);
> +
> +       err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth,
> +                       &key_handle);
> +       if (!err)
> +               printf("Key handle is 0x%x\n", key_handle);
> +
> +       return convert_return_code(err);
> +}
> +
> +static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag,
> +               int argc, char * const argv[])
> +{
> +       uint32_t key_handle, err;
> +       uint8_t usage_auth[20];
> +       uint8_t pub_key_buffer[288];
> +       size_t pub_key_len = sizeof(pub_key_buffer);
> +
> +       if (argc < 3)
> +               return CMD_RET_USAGE;
> +
> +       key_handle = simple_strtoul(argv[1], NULL, 0);
> +       if (strlen(argv[2]) != 40)
> +               return CMD_RET_FAILURE;
> +       parse_byte_string(argv[2], usage_auth, NULL);
> +
> +       err = tpm_get_pub_key_oiap(key_handle, usage_auth,
> +                       pub_key_buffer, &pub_key_len);
> +       if (!err) {
> +               printf("dump of received pub key structure:\n");
> +               print_byte_string(pub_key_buffer, pub_key_len);
> +       }
> +       return convert_return_code(err);
> +}
> +
> +TPM_COMMAND_NO_ARG(tpm_end_oiap)
> +
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
> +
>  #define MAKE_TPM_CMD_ENTRY(cmd) \
>         U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
>
> @@ -590,6 +656,16 @@ static cmd_tbl_t tpm_commands[] = {
>                         do_tpm_nv_read, "", ""),
>         U_BOOT_CMD_MKENT(nv_write, 0, 1,
>                         do_tpm_nv_write, "", ""),
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +       U_BOOT_CMD_MKENT(oiap, 0, 1,
> +                       do_tpm_oiap, "", ""),
> +       U_BOOT_CMD_MKENT(end_oiap, 0, 1,
> +                       do_tpm_end_oiap, "", ""),
> +       U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1,
> +                       do_tpm_load_key2_oiap, "", ""),
> +       U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1,
> +                       do_tpm_get_pub_key_oiap, "", ""),
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
>  };
>
>  static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> @@ -638,6 +714,16 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
>  "  get_capability cap_area sub_cap addr count\n"
>  "    - Read <count> bytes of TPM capability indexed by <cap_area> and\n"
>  "      <sub_cap> to memory address <addr>.\n"
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +"Storage functions\n"
> +"  loadkey2_oiap parent_handle key_addr key_len usage_auth\n"
> +"    - loads a key data from memory address <key_addr>, <key_len> bytes\n"
> +"      into TPM using the parent key <parent_handle> with authorization\n"
> +"      <usage_auth> (20 bytes hex string).\n"
> +"  get_pub_key_oiap key_handle usage_auth\n"
> +"    - get the public key portion of a loaded key <key_handle> using\n"
> +"      authorization <usage auth> (20 bytes hex string)\n"
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
>  "Endorsement Key Handling Commands:\n"
>  "  read_pubek addr count\n"
>  "    - Read <count> bytes of the public endorsement key to memory\n"
> @@ -648,6 +734,13 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
>  "      <digest_hex_string>\n"
>  "  pcr_read index addr count\n"
>  "    - Read <count> bytes from PCR <index> to memory address <addr>.\n"
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +"Authorization Sessions\n"
> +"  oiap\n"
> +"    - setup an OIAP session\n"
> +"  end_oiap\n"
> +"    - terminates an active OIAP session\n"
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
>  "Non-volatile Storage Commands:\n"
>  "  nv_define_space index permission size\n"
>  "    - Establish a space at index <index> with <permission> of <size> bytes.\n"
> diff --git a/include/tpm.h b/include/tpm.h
> index 7219b73..5e9f832 100644
> --- a/include/tpm.h
> +++ b/include/tpm.h
> @@ -1,5 +1,6 @@
>  /*
>   * Copyright (c) 2013 The Chromium OS Authors.
> + * Coypright (c) 2013 Guntermann & Drunck GmbH
>   *
>   * See file CREDITS for list of people who contributed to this
>   * project.
> @@ -54,6 +55,120 @@ enum tpm_nv_index {
>  };
>
>  /**
> + * TPM return codes as defined in the TCG Main specification
> + * (TPM Main Part 2 Structures; Specification version 1.2)
> + */
> +enum tpm_return_code {
> +       TPM_BASE        = 0x00000000,
> +       TPM_NON_FATAL   = 0x00000800,
> +       TPM_SUCCESS     = TPM_BASE,
> +       /* TPM-defined fatal error codes */
> +       TPM_AUTHFAIL                    = TPM_BASE +  1,
> +       TPM_BADINDEX                    = TPM_BASE +  2,
> +       TPM_BAD_PARAMETER               = TPM_BASE +  3,
> +       TPM_AUDITFAILURE                = TPM_BASE +  4,
> +       TPM_CLEAR_DISABLED              = TPM_BASE +  5,
> +       TPM_DEACTIVATED                 = TPM_BASE +  6,
> +       TPM_DISABLED                    = TPM_BASE +  7,
> +       TPM_DISABLED_CMD                = TPM_BASE +  8,
> +       TPM_FAIL                        = TPM_BASE +  9,
> +       TPM_BAD_ORDINAL                 = TPM_BASE + 10,
> +       TPM_INSTALL_DISABLED            = TPM_BASE + 11,
> +       TPM_INVALID_KEYHANDLE           = TPM_BASE + 12,
> +       TPM_KEYNOTFOUND                 = TPM_BASE + 13,
> +       TPM_INAPPROPRIATE_ENC           = TPM_BASE + 14,
> +       TPM_MIGRATE_FAIL                = TPM_BASE + 15,
> +       TPM_INVALID_PCR_INFO            = TPM_BASE + 16,
> +       TPM_NOSPACE                     = TPM_BASE + 17,
> +       TPM_NOSRK                       = TPM_BASE + 18,
> +       TPM_NOTSEALED_BLOB              = TPM_BASE + 19,
> +       TPM_OWNER_SET                   = TPM_BASE + 20,
> +       TPM_RESOURCES                   = TPM_BASE + 21,
> +       TPM_SHORTRANDOM                 = TPM_BASE + 22,
> +       TPM_SIZE                        = TPM_BASE + 23,
> +       TPM_WRONGPCRVAL                 = TPM_BASE + 24,
> +       TPM_BAD_PARAM_SIZE              = TPM_BASE + 25,
> +       TPM_SHA_THREAD                  = TPM_BASE + 26,
> +       TPM_SHA_ERROR                   = TPM_BASE + 27,
> +       TPM_FAILEDSELFTEST              = TPM_BASE + 28,
> +       TPM_AUTH2FAIL                   = TPM_BASE + 29,
> +       TPM_BADTAG                      = TPM_BASE + 30,
> +       TPM_IOERROR                     = TPM_BASE + 31,
> +       TPM_ENCRYPT_ERROR               = TPM_BASE + 32,
> +       TPM_DECRYPT_ERROR               = TPM_BASE + 33,
> +       TPM_INVALID_AUTHHANDLE          = TPM_BASE + 34,
> +       TPM_NO_ENDORSEMENT              = TPM_BASE + 35,
> +       TPM_INVALID_KEYUSAGE            = TPM_BASE + 36,
> +       TPM_WRONG_ENTITYTYPE            = TPM_BASE + 37,
> +       TPM_INVALID_POSTINIT            = TPM_BASE + 38,
> +       TPM_INAPPROPRIATE_SIG           = TPM_BASE + 39,
> +       TPM_BAD_KEY_PROPERTY            = TPM_BASE + 40,
> +       TPM_BAD_MIGRATION               = TPM_BASE + 41,
> +       TPM_BAD_SCHEME                  = TPM_BASE + 42,
> +       TPM_BAD_DATASIZE                = TPM_BASE + 43,
> +       TPM_BAD_MODE                    = TPM_BASE + 44,
> +       TPM_BAD_PRESENCE                = TPM_BASE + 45,
> +       TPM_BAD_VERSION                 = TPM_BASE + 46,
> +       TPM_NO_WRAP_TRANSPORT           = TPM_BASE + 47,
> +       TPM_AUDITFAIL_UNSUCCESSFUL      = TPM_BASE + 48,
> +       TPM_AUDITFAIL_SUCCESSFUL        = TPM_BASE + 49,
> +       TPM_NOTRESETABLE                = TPM_BASE + 50,
> +       TPM_NOTLOCAL                    = TPM_BASE + 51,
> +       TPM_BAD_TYPE                    = TPM_BASE + 52,
> +       TPM_INVALID_RESOURCE            = TPM_BASE + 53,
> +       TPM_NOTFIPS                     = TPM_BASE + 54,
> +       TPM_INVALID_FAMILY              = TPM_BASE + 55,
> +       TPM_NO_NV_PERMISSION            = TPM_BASE + 56,
> +       TPM_REQUIRES_SIGN               = TPM_BASE + 57,
> +       TPM_KEY_NOTSUPPORTED            = TPM_BASE + 58,
> +       TPM_AUTH_CONFLICT               = TPM_BASE + 59,
> +       TPM_AREA_LOCKED                 = TPM_BASE + 60,
> +       TPM_BAD_LOCALITY                = TPM_BASE + 61,
> +       TPM_READ_ONLY                   = TPM_BASE + 62,
> +       TPM_PER_NOWRITE                 = TPM_BASE + 63,
> +       TPM_FAMILY_COUNT                = TPM_BASE + 64,
> +       TPM_WRITE_LOCKED                = TPM_BASE + 65,
> +       TPM_BAD_ATTRIBUTES              = TPM_BASE + 66,
> +       TPM_INVALID_STRUCTURE           = TPM_BASE + 67,
> +       TPM_KEY_OWNER_CONTROL           = TPM_BASE + 68,
> +       TPM_BAD_COUNTER                 = TPM_BASE + 69,
> +       TPM_NOT_FULLWRITE               = TPM_BASE + 70,
> +       TPM_CONTEXT_GAP                 = TPM_BASE + 71,
> +       TPM_MAXNVWRITES                 = TPM_BASE + 72,
> +       TPM_NOOPERATOR                  = TPM_BASE + 73,
> +       TPM_RESOURCEMISSING             = TPM_BASE + 74,
> +       TPM_DELEGATE_LOCK               = TPM_BASE + 75,
> +       TPM_DELEGATE_FAMILY             = TPM_BASE + 76,
> +       TPM_DELEGATE_ADMIN              = TPM_BASE + 77,
> +       TPM_TRANSPORT_NOTEXCLUSIVE      = TPM_BASE + 78,
> +       TPM_OWNER_CONTROL               = TPM_BASE + 79,
> +       TPM_DAA_RESOURCES               = TPM_BASE + 80,
> +       TPM_DAA_INPUT_DATA0             = TPM_BASE + 81,
> +       TPM_DAA_INPUT_DATA1             = TPM_BASE + 82,
> +       TPM_DAA_ISSUER_SETTINGS         = TPM_BASE + 83,
> +       TPM_DAA_TPM_SETTINGS            = TPM_BASE + 84,
> +       TPM_DAA_STAGE                   = TPM_BASE + 85,
> +       TPM_DAA_ISSUER_VALIDITY         = TPM_BASE + 86,
> +       TPM_DAA_WRONG_W                 = TPM_BASE + 87,
> +       TPM_BAD_HANDLE                  = TPM_BASE + 88,
> +       TPM_BAD_DELEGATE                = TPM_BASE + 89,
> +       TPM_BADCONTEXT                  = TPM_BASE + 90,
> +       TPM_TOOMANYCONTEXTS             = TPM_BASE + 91,
> +       TPM_MA_TICKET_SIGNATURE         = TPM_BASE + 92,
> +       TPM_MA_DESTINATION              = TPM_BASE + 93,
> +       TPM_MA_SOURCE                   = TPM_BASE + 94,
> +       TPM_MA_AUTHORITY                = TPM_BASE + 95,
> +       TPM_PERMANENTEK                 = TPM_BASE + 97,
> +       TPM_BAD_SIGNATURE               = TPM_BASE + 98,
> +       TPM_NOCONTEXTSPACE              = TPM_BASE + 99,
> +       /* TPM-defined non-fatal errors */
> +       TPM_RETRY               = TPM_BASE + TPM_NON_FATAL,
> +       TPM_NEEDS_SELFTEST      = TPM_BASE + TPM_NON_FATAL + 1,
> +       TPM_DOING_SELFTEST      = TPM_BASE + TPM_NON_FATAL + 2,
> +       TPM_DEFEND_LOCK_RUNNING = TPM_BASE + TPM_NON_FATAL + 3,
> +};
> +
> +/**
>   * Initialize TPM device.  It must be called before any TPM commands.
>   *
>   * @return 0 on success, non-0 on error.
> @@ -201,4 +316,63 @@ uint32_t tpm_physical_set_deactivated(uint8_t state);
>  uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
>                 void *cap, size_t count);
>
> +/**
> + * Issue a TPM_FlushSpecific command for a AUTH ressource.
> + *
> + * @param auth_handle  handle of the auth session
> + * @return return code of the operation
> + */
> +uint32_t tpm_terminate_auth_session(uint32_t auth_handle);
> +
> +/**
> + * Issue a TPM_OIAP command to setup an object independant authorization
> + * session.
> + * Information about the session is stored internally.
> + * If there was already an OIAP session active it is terminated and a new
> + * session is set up.
> + *
> + * @param auth_handle  pointer to the (new) auth handle or NULL.
> + * @return return code of the operation
> + */
> +uint32_t tpm_oiap(uint32_t *auth_handle);
> +
> +/**
> + * Ends an active OIAP session.
> + *
> + * @return return code of the operation
> + */
> +uint32_t tpm_end_oiap(void);
> +
> +/**
> + * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating
> + * the usage of the parent key.
> + *
> + * @param parent_handle        handle of the parent key.
> + * @param key          pointer to the key structure (TPM_KEY or TPM_KEY12).
> + * @param key_length   size of the key structure
> + * @param parent_key_usage_auth        usage auth for the parent key
> + * @param key_handle   pointer to the key handle
> + * @return return code of the operation
> + */
> +uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
> +               const void *key, size_t key_length,
> +               const void *parent_key_usage_auth,
> +               uint32_t *key_handle);
> +
> +/**
> + * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for
> + * authenticating the usage of the key.
> + *
> + * @param key_handle   handle of the key
> + * @param usage_auth   usage auth for the key
> + * @param pubkey       pointer to the pub key buffer; may be NULL if the pubkey
> + *                     should not be stored.
> + * @param pubkey_len   pointer to the pub key buffer len. On entry: the size of
> + *                     the provided pubkey buffer. On successful exit: the size
> + *                     of the stored TPM_PUBKEY structure (iff pubkey != NULL).
> + * @return return code of the operation
> + */
> +uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
> +               void *pubkey, size_t *pubkey_len);
> +
>  #endif /* __TPM_H */
> diff --git a/lib/tpm.c b/lib/tpm.c
> index 42c9bea..87bf188 100644
> --- a/lib/tpm.c
> +++ b/lib/tpm.c
> @@ -1,5 +1,6 @@
>  /*
>   * Copyright (c) 2013 The Chromium OS Authors.
> + * Coypright (c) 2013 Guntermann & Drunck GmbH
>   *
>   * See file CREDITS for list of people who contributed to this
>   * project.
> @@ -22,6 +23,7 @@
>
>  #include <common.h>
>  #include <stdarg.h>
> +#include <sha1.h>
>  #include <tpm.h>
>  #include <asm/unaligned.h>
>
> @@ -35,8 +37,31 @@ enum {
>         TPM_REQUEST_HEADER_LENGTH       = 10,
>         TPM_RESPONSE_HEADER_LENGTH      = 10,
>         PCR_DIGEST_LENGTH               = 20,
> +       DIGEST_LENGTH                   = 20,
> +       TPM_REQUEST_AUTH_LENGTH         = 45,
> +       TPM_RESPONSE_AUTH_LENGTH        = 41,
> +       /* some max lengths, valid for RSA keys <= 2048 bits */
> +       TPM_KEY12_MAX_LENGTH            = 618,
> +       TPM_PUBKEY_MAX_LENGTH           = 288,
>  };
>
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +
> +#ifndef CONFIG_SHA1
> +#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
> +#endif /* !CONFIG_SHA1 */
> +
> +struct session_data {
> +       int             valid;
> +       uint32_t        handle;
> +       uint8_t         nonce_even[DIGEST_LENGTH];
> +       uint8_t         nonce_odd[DIGEST_LENGTH];
> +};
> +
> +static struct session_data oiap_session = {0, };
> +
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
> +
>  /**
>   * Pack data into a byte string.  The data types are specified in
>   * the format string: 'b' means unsigned byte, 'w' unsigned word,
> @@ -235,7 +260,7 @@ static uint32_t tpm_sendrecv_command(const void *command,
>                         response, &response_length);
>         if (err)
>                 return TPM_LIB_ERROR;
> -       if (response)
> +       if (size_ptr)
>                 *size_ptr = response_length;

Thanks for catching this!

>
>         return tpm_return_code(response);
> @@ -579,3 +604,324 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
>
>         return 0;
>  }
> +
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +
> +/**
> + * Fill an authentication block in a request.
> + * This func can create the first as well as the second auth block (for
> + * double authorized commands).
> + *
> + * @param request      pointer to the request (w/ uninitialised auth data)
> + * @param request_len0 length of the request without auth data
> + * @param handles_len  length of the handles area in request
> + * @param auth_session pointer to the (valid) auth session to be used
> + * @param request_auth pointer to the auth block of the request to be filled
> + * @param auth         authentication data (HMAC key)
> + */
> +static uint32_t create_request_auth(const void *request, size_t request_len0,
> +       size_t handles_len,
> +       struct session_data *auth_session,
> +       void *request_auth, const void *auth)
> +{
> +       uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
> +       sha1_context hash_ctx;
> +       const size_t command_code_offset = 6;
> +       const size_t auth_nonce_odd_offset = 4;
> +       const size_t auth_continue_offset = 24;
> +       const size_t auth_auth_offset = 25;
> +
> +       if (!auth_session || !auth_session->valid)
> +               return TPM_LIB_ERROR;
> +
> +       sha1_starts(&hash_ctx);
> +       sha1_update(&hash_ctx, request + command_code_offset, 4);
> +       if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
> +               sha1_update(&hash_ctx,
> +                       request + TPM_REQUEST_HEADER_LENGTH + handles_len,
> +                       request_len0 - TPM_REQUEST_HEADER_LENGTH - handles_len);
> +       sha1_finish(&hash_ctx, hmac_data);
> +
> +       sha1_starts(&hash_ctx);
> +       sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
> +       sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
> +       sha1_finish(&hash_ctx, auth_session->nonce_odd);
> +
> +       if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
> +                       0, auth_session->handle,
> +                       auth_nonce_odd_offset, auth_session->nonce_odd,
> +                       DIGEST_LENGTH,
> +                       auth_continue_offset, 1))
> +               return TPM_LIB_ERROR;
> +       if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
> +                               DIGEST_LENGTH,
> +                               auth_session->nonce_even,
> +                               DIGEST_LENGTH,
> +                               2 * DIGEST_LENGTH,
> +                               request_auth + auth_nonce_odd_offset,
> +                               DIGEST_LENGTH + 1))
> +               return TPM_LIB_ERROR;
> +       sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
> +               request_auth + auth_auth_offset);
> +
> +       return TPM_SUCCESS;
> +}
> +
> +/**
> + * Verify an authentication block in a response.
> + * Since this func updates the nonce_even in the session data it has to be
> + * called when receiving a succesfull AUTH response.
> + * This func can verify the first as well as the second auth block (for
> + * double authorized commands).
> + *
> + * @param command_code command code of the request
> + * @param response     pointer to the request (w/ uninitialised auth data)
> + * @param handles_len  length of the handles area in response
> + * @param auth_session pointer to the (valid) auth session to be used
> + * @param response_auth        pointer to the auth block of the response to be verified
> + * @param auth         authentication data (HMAC key)
> + */
> +static uint32_t verify_response_auth(uint32_t command_code,
> +       const void *response, size_t response_len0,
> +       size_t handles_len,
> +       struct session_data *auth_session,
> +       const void *response_auth, const void *auth)
> +{
> +       uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
> +       uint8_t computed_auth[DIGEST_LENGTH];
> +       sha1_context hash_ctx;
> +       const size_t return_code_offset = 6;
> +       const size_t auth_continue_offset = 20;
> +       const size_t auth_auth_offset = 21;
> +       uint8_t auth_continue;
> +
> +       if (!auth_session || !auth_session->valid)
> +               return TPM_AUTHFAIL;
> +       if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
> +                               0, command_code))
> +               return TPM_LIB_ERROR;
> +       if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
> +               return TPM_LIB_ERROR;
> +
> +       sha1_starts(&hash_ctx);
> +       sha1_update(&hash_ctx, response + return_code_offset, 4);
> +       sha1_update(&hash_ctx, hmac_data, 4);
> +       if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
> +               sha1_update(&hash_ctx,
> +                       response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
> +                       response_len0 - TPM_RESPONSE_HEADER_LENGTH
> +                       - handles_len);
> +       sha1_finish(&hash_ctx, hmac_data);
> +
> +       memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
> +       auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
> +       if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
> +                               DIGEST_LENGTH,
> +                               response_auth,
> +                               DIGEST_LENGTH,
> +                               2 * DIGEST_LENGTH,
> +                               auth_session->nonce_odd,
> +                               DIGEST_LENGTH,
> +                               3 * DIGEST_LENGTH,
> +                               auth_continue))
> +               return TPM_LIB_ERROR;
> +
> +       sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
> +               computed_auth);
> +
> +       if (memcmp(computed_auth, response_auth + auth_auth_offset,
> +                       DIGEST_LENGTH))
> +               return TPM_AUTHFAIL;
> +
> +       return TPM_SUCCESS;
> +}
> +
> +
> +uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
> +{
> +       const uint8_t command[18] = {
> +               0x00, 0xc1,             /* TPM_TAG */
> +               0x00, 0x00, 0x00, 0x00, /* parameter size */
> +               0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
> +               0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
> +               0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
> +       };
> +       const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
> +       uint8_t request[COMMAND_BUFFER_SIZE];
> +
> +       if (pack_byte_string(request, sizeof(request), "sd",
> +                       0, command, sizeof(command),
> +                       req_handle_offset, auth_handle))
> +               return TPM_LIB_ERROR;
> +       if (oiap_session.valid && oiap_session.handle == auth_handle)
> +               oiap_session.valid = 0;
> +
> +       return tpm_sendrecv_command(request, NULL, NULL);
> +}
> +
> +uint32_t tpm_end_oiap(void)
> +{
> +       uint32_t err = TPM_SUCCESS;
> +       if (oiap_session.valid)
> +               err = tpm_terminate_auth_session(oiap_session.handle);
> +       return err;
> +}
> +
> +uint32_t tpm_oiap(uint32_t *auth_handle)
> +{
> +       const uint8_t command[10] = {
> +               0x00, 0xc1,             /* TPM_TAG */
> +               0x00, 0x00, 0x00, 0x0a, /* parameter size */
> +               0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
> +       };
> +       const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
> +       const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
> +       uint8_t response[COMMAND_BUFFER_SIZE];
> +       size_t response_length = sizeof(response);
> +       uint32_t err;
> +
> +       if (oiap_session.valid)
> +               tpm_terminate_auth_session(oiap_session.handle);
> +
> +       err = tpm_sendrecv_command(command, response, &response_length);
> +       if (err)
> +               return err;
> +       if (unpack_byte_string(response, response_length, "ds",
> +                       res_auth_handle_offset, &oiap_session.handle,
> +                       res_nonce_even_offset, &oiap_session.nonce_even,
> +                       (uint32_t)DIGEST_LENGTH))
> +               return TPM_LIB_ERROR;
> +       oiap_session.valid = 1;
> +       if (auth_handle)
> +               *auth_handle = oiap_session.handle;
> +       return 0;
> +}
> +
> +uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
> +               const void *key, size_t key_length,
> +               const void *parent_key_usage_auth,
> +               uint32_t *key_handle)
> +{
> +       const uint8_t command[14] = {
> +               0x00, 0xc2,             /* TPM_TAG */
> +               0x00, 0x00, 0x00, 0x00, /* parameter size */
> +               0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
> +               0x00, 0x00, 0x00, 0x00, /* parent handle */
> +       };
> +       const size_t req_size_offset = 2;
> +       const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
> +       const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
> +       const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
> +       uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
> +                       + TPM_REQUEST_AUTH_LENGTH];
> +       uint8_t response[COMMAND_BUFFER_SIZE];
> +       size_t response_length = sizeof(response);
> +       uint32_t err;
> +
> +       if (!oiap_session.valid) {
> +               err = tpm_oiap(NULL);
> +               if (err)
> +                       return err;
> +       }
> +       if (pack_byte_string(request, sizeof(request), "sdds",
> +                       0, command, sizeof(command),
> +                       req_size_offset,
> +                       sizeof(command) + key_length + TPM_REQUEST_AUTH_LENGTH,
> +                       req_parent_handle_offset, parent_handle,
> +                       req_key_offset, key, key_length
> +               ))
> +               return TPM_LIB_ERROR;
> +
> +       err = create_request_auth(request, sizeof(command) + key_length, 4,
> +                       &oiap_session,
> +                       request + sizeof(command) + key_length,
> +                       parent_key_usage_auth);
> +       if (err)
> +               return err;
> +       err = tpm_sendrecv_command(request, response, &response_length);
> +       if (err) {
> +               if (err == TPM_AUTHFAIL)
> +                       oiap_session.valid = 0;
> +               return err;
> +       }
> +
> +       err = verify_response_auth(0x00000041, response,
> +                       response_length - TPM_RESPONSE_AUTH_LENGTH,
> +                       4, &oiap_session,
> +                       response + response_length - TPM_RESPONSE_AUTH_LENGTH,
> +                       parent_key_usage_auth);
> +       if (err)
> +               return err;
> +
> +       if (key_handle) {
> +               if (unpack_byte_string(response, response_length, "d",
> +                               res_handle_offset, key_handle))
> +                       return TPM_LIB_ERROR;
> +       }
> +
> +       return 0;
> +}
> +
> +uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
> +                       void *pubkey, size_t *pubkey_len)
> +{
> +       const uint8_t command[14] = {
> +               0x00, 0xc2,             /* TPM_TAG */
> +               0x00, 0x00, 0x00, 0x00, /* parameter size */
> +               0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
> +               0x00, 0x00, 0x00, 0x00, /* key handle */
> +       };
> +       const size_t req_size_offset = 2;
> +       const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
> +       const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
> +       uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
> +       uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
> +                       + TPM_RESPONSE_AUTH_LENGTH];
> +       size_t response_length = sizeof(response);
> +       uint32_t err;
> +
> +       if (!oiap_session.valid) {
> +               err = tpm_oiap(NULL);
> +               if (err)
> +                       return err;
> +       }
> +       if (pack_byte_string(request, sizeof(request), "sdd",
> +                       0, command, sizeof(command),
> +                       req_size_offset,
> +                       (uint32_t)(sizeof(command) + TPM_REQUEST_AUTH_LENGTH),
> +                       req_key_handle_offset, key_handle
> +               ))
> +               return TPM_LIB_ERROR;
> +       err = create_request_auth(request, sizeof(command), 4, &oiap_session,
> +                       request + sizeof(command), usage_auth);
> +       if (err)
> +               return err;
> +       err = tpm_sendrecv_command(request, response, &response_length);
> +       if (err) {
> +               if (err == TPM_AUTHFAIL)
> +                       oiap_session.valid = 0;
> +               return err;
> +       }
> +       err = verify_response_auth(0x00000021, response,
> +                       response_length - TPM_RESPONSE_AUTH_LENGTH,
> +                       0, &oiap_session,
> +                       response + response_length - TPM_RESPONSE_AUTH_LENGTH,
> +                       usage_auth);
> +       if (err)
> +               return err;
> +
> +       if (pubkey) {
> +               if ((response_length - TPM_RESPONSE_HEADER_LENGTH
> +                       - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
> +                       return TPM_LIB_ERROR;
> +               *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
> +                       - TPM_RESPONSE_AUTH_LENGTH;
> +               memcpy(pubkey, response + res_pubkey_offset,
> +                       response_length - TPM_RESPONSE_HEADER_LENGTH
> +                               - TPM_RESPONSE_AUTH_LENGTH);
> +       }
> +
> +       return 0;
> +}
> +
> +#endif /* CONFIG_TPM_AUTH_SESSIONS */
> --
> 1.7.10.4
>
>
Tom Rini April 22, 2013, 6:37 p.m. UTC | #2
On Mon, Apr 22, 2013 at 01:06:40PM +0200, Dirk Eibach wrote:

> From: Reinhard Pfau <pfau@gdsys.de>
> 
> Extend the tpm library with support for single authorized (AUTH1) commands
> as specified in the TCG Main Specification 1.2. (The internally used helper
> functions are implemented in a way that they could also be used for double
> authorized commands if someone needs it.)
> 
> Provide enums with the return codes from the TCG Main specification.
> 
> For now only a single OIAP session is supported.
> 
> OIAP authorized version of the commands TPM_LoadKey2 and TPM_GetPubKey are
> provided. Both features are available using the 'tpm' command, too.
> 
> Authorized commands are enabled with CONFIG_TPM_AUTH_SESSIONS. (Note that
> this also requires CONFIG_SHA1 to be enabled.)
> 
> Signed-off-by: Reinhard Pfau <pfau@gdsys.de>
> 
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>

I'm glad to see this as it helps further the TPM related discussions.

[snip]
> +#ifdef CONFIG_TPM_AUTH_SESSIONS
> +
> +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag,
> +		int argc, char * const argv[])

checkpatch warning.  Please run ./tools/checkpatch.pl and fix
everything.

[snip]
> +	uint8_t usage_auth[20];
[snip]
> +	if (strlen(argv[4]) != 40)
> +		return CMD_RET_FAILURE;
[snip]
> +	uint8_t usage_auth[20];
> +	uint8_t pub_key_buffer[288];

These are just a few examples of array sizes that clearly have a
specific meaning (288 == TPM_PUBKEY_MAX_LENGTH I think), that we should
be using the name for, for clarity.

[snip]
>  /**
> + * TPM return codes as defined in the TCG Main specification
> + * (TPM Main Part 2 Structures; Specification version 1.2)
> + */
> +enum tpm_return_code {
> +	TPM_BASE	= 0x00000000,
> +	TPM_NON_FATAL	= 0x00000800,
> +	TPM_SUCCESS	= TPM_BASE,
> +	/* TPM-defined fatal error codes */
> +	TPM_AUTHFAIL			= TPM_BASE +  1,
[snip]
> +	TPM_BADINDEX			= TPM_BASE +  2,

I don't like this form, and it's not what we usually use.  It should be,
roughly:
enum tpm_return_code {
 TPM_SUCCESS = 0,
 /* TPM-defined fatal error codes. */
 TPM_BAD_PARAMETER,
 TPM_AUDITFAILURE,
 ...
 /* TPM-defined non-fatal error codes. */
 TPM_RETRY = 0x800,
 TPM_NEEDS_SELFTEST,
 ...
}
Pfau, Reinhard April 23, 2013, 12:12 p.m. UTC | #3
Hi,

> -----Original Message-----
> From: u-boot-bounces@lists.denx.de 
> [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Tom Rini
> Sent: Monday, April 22, 2013 8:37 PM
> To: Eibach, Dirk
> Cc: u-boot@lists.denx.de
> Subject: (Mixed security state) Re: [U-Boot] [PATCH 1/6] tpm: 
> add AUTH1 cmds for LoadKey2 and GetPubKey
> 
> On Mon, Apr 22, 2013 at 01:06:40PM +0200, Dirk Eibach wrote:
> 
> > From: Reinhard Pfau <pfau@gdsys.de>
> > 
> > Extend the tpm library with support for single authorized 
> (AUTH1) commands
> > as specified in the TCG Main Specification 1.2. (The 
> internally used helper
> > functions are implemented in a way that they could also be 
> used for double
> > authorized commands if someone needs it.)
> > 
> > Provide enums with the return codes from the TCG Main specification.
> > 
> > For now only a single OIAP session is supported.
> > 
> > OIAP authorized version of the commands TPM_LoadKey2 and 
> TPM_GetPubKey are
> > provided. Both features are available using the 'tpm' command, too.
> > 
> > Authorized commands are enabled with 
> CONFIG_TPM_AUTH_SESSIONS. (Note that
> > this also requires CONFIG_SHA1 to be enabled.)
> > 
> > Signed-off-by: Reinhard Pfau <pfau@gdsys.de>
> > 
> > Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> 
> I'm glad to see this as it helps further the TPM related discussions.
> 
> [snip]
> > +#ifdef CONFIG_TPM_AUTH_SESSIONS
> > +
> > +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag,
> > +		int argc, char * const argv[])
> 
> checkpatch warning.  Please run ./tools/checkpatch.pl and fix
> everything.

OK; will be done.

> 
> [snip]
> > +	uint8_t usage_auth[20];
> [snip]
> > +	if (strlen(argv[4]) != 40)
> > +		return CMD_RET_FAILURE;
> [snip]
> > +	uint8_t usage_auth[20];
> > +	uint8_t pub_key_buffer[288];
> 
> These are just a few examples of array sizes that clearly have a
> specific meaning (288 == TPM_PUBKEY_MAX_LENGTH I think), that 
> we should
> be using the name for, for clarity.

Like we did in lib/tpm.c; sounds like a good idea. Will be done, too.

> 
> [snip]
> >  /**
> > + * TPM return codes as defined in the TCG Main specification
> > + * (TPM Main Part 2 Structures; Specification version 1.2)
> > + */
> > +enum tpm_return_code {
> > +	TPM_BASE	= 0x00000000,
> > +	TPM_NON_FATAL	= 0x00000800,
> > +	TPM_SUCCESS	= TPM_BASE,
> > +	/* TPM-defined fatal error codes */
> > +	TPM_AUTHFAIL			= TPM_BASE +  1,
> [snip]
> > +	TPM_BADINDEX			= TPM_BASE +  2,
> 
> I don't like this form, and it's not what we usually use.  It 
> should be,
> roughly:
> enum tpm_return_code {
>  TPM_SUCCESS = 0,
>  /* TPM-defined fatal error codes. */
>  TPM_BAD_PARAMETER,
>  TPM_AUDITFAILURE,
>  ...
>  /* TPM-defined non-fatal error codes. */
>  TPM_RETRY = 0x800,
>  TPM_NEEDS_SELFTEST,
>  ...
> }

Well, the way I wrote the constants is intentionally since the return
codes are defined like this in the TCG specification.
In the spec the return codes are found in a table with name and value;
and the value is expressed as sum based on TPM_BASE.
(See TCG published spec: "TPM Main Part 2 TPM Structures; Specification
version 1.2" chapter 16 ("Return Codes").)

This way it might be easier to keep the constants in sync with (future)
versions of the TCG spec :-)
So I would like to keep it as it is.


Greetings,
Reinhard.
Tom Rini April 23, 2013, 2:47 p.m. UTC | #4
On Tue, Apr 23, 2013 at 02:12:52PM +0200, Pfau, Reinhard wrote:
> 
> Hi,
> 
> > -----Original Message-----
> > From: u-boot-bounces@lists.denx.de 
> > [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Tom Rini
> > Sent: Monday, April 22, 2013 8:37 PM
> > To: Eibach, Dirk
> > Cc: u-boot@lists.denx.de
> > Subject: (Mixed security state) Re: [U-Boot] [PATCH 1/6] tpm: 
> > add AUTH1 cmds for LoadKey2 and GetPubKey
> > 
> > On Mon, Apr 22, 2013 at 01:06:40PM +0200, Dirk Eibach wrote:
> > 
> > > From: Reinhard Pfau <pfau@gdsys.de>
[snip]
> > [snip]
> > >  /**
> > > + * TPM return codes as defined in the TCG Main specification
> > > + * (TPM Main Part 2 Structures; Specification version 1.2)
> > > + */
> > > +enum tpm_return_code {
> > > +	TPM_BASE	= 0x00000000,
> > > +	TPM_NON_FATAL	= 0x00000800,
> > > +	TPM_SUCCESS	= TPM_BASE,
> > > +	/* TPM-defined fatal error codes */
> > > +	TPM_AUTHFAIL			= TPM_BASE +  1,
> > [snip]
> > > +	TPM_BADINDEX			= TPM_BASE +  2,
> > 
> > I don't like this form, and it's not what we usually use.  It 
> > should be,
> > roughly:
> > enum tpm_return_code {
> >  TPM_SUCCESS = 0,
> >  /* TPM-defined fatal error codes. */
> >  TPM_BAD_PARAMETER,
> >  TPM_AUDITFAILURE,
> >  ...
> >  /* TPM-defined non-fatal error codes. */
> >  TPM_RETRY = 0x800,
> >  TPM_NEEDS_SELFTEST,
> >  ...
> > }
> 
> Well, the way I wrote the constants is intentionally since the return
> codes are defined like this in the TCG specification.
> In the spec the return codes are found in a table with name and value;
> and the value is expressed as sum based on TPM_BASE.
> (See TCG published spec: "TPM Main Part 2 TPM Structures; Specification
> version 1.2" chapter 16 ("Return Codes").)
> 
> This way it might be easier to keep the constants in sync with (future)
> versions of the TCG spec :-)
> So I would like to keep it as it is.

OK, I pulled up the doc and I see what you mean.  Yes, it's OK to do
that in this case here.  Thanks!
diff mbox

Patch

diff --git a/README b/README
index 0bc0af5..58b2ee5 100644
--- a/README
+++ b/README
@@ -1210,6 +1210,20 @@  The following options need to be configured:
 			to. Contemporary x86 systems usually map it at
 			0xfed40000.
 
+		CONFIG_CMD_TPM
+		Add tpm monitor functions.
+		Requires CONFIG_TPM. If CONFIG_TPM_AUTH_SESSIONS is set, also
+		provides monitor access to authorized functions.
+
+		CONFIG_TPM
+		Define this to enable the TPM support library which provides
+		functional interfaces to some TPM commands.
+		Requires support for a TPM device.
+
+		CONFIG_TPM_AUTH_SESSIONS
+		Define this to enable authorized functions in the TPM library.
+		Requires CONFIG_TPM and CONFIG_SHA1.
+
 - USB Support:
 		At the moment only the UHCI host controller is
 		supported (PIP405, MIP405, MPC5200); define
diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c
index 46fae18..c8767a4 100644
--- a/common/cmd_tpm.c
+++ b/common/cmd_tpm.c
@@ -546,6 +546,72 @@  static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,
 	return convert_return_code(err);
 }
 
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+
+static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	uint32_t auth_handle, err;
+
+	err = tpm_oiap(&auth_handle);
+
+	return convert_return_code(err);
+}
+
+static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	uint32_t parent_handle, key_len, key_handle, err;
+	uint8_t usage_auth[20];
+	void *key;
+
+	if (argc < 5)
+		return CMD_RET_USAGE;
+
+	parent_handle = simple_strtoul(argv[1], NULL, 0);
+	key = (void *)simple_strtoul(argv[2], NULL, 0);
+	key_len = simple_strtoul(argv[3], NULL, 0);
+	if (strlen(argv[4]) != 40)
+		return CMD_RET_FAILURE;
+	parse_byte_string(argv[4], usage_auth, NULL);
+
+	err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth,
+			&key_handle);
+	if (!err)
+		printf("Key handle is 0x%x\n", key_handle);
+
+	return convert_return_code(err);
+}
+
+static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag,
+		int argc, char * const argv[])
+{
+	uint32_t key_handle, err;
+	uint8_t usage_auth[20];
+	uint8_t pub_key_buffer[288];
+	size_t pub_key_len = sizeof(pub_key_buffer);
+
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	key_handle = simple_strtoul(argv[1], NULL, 0);
+	if (strlen(argv[2]) != 40)
+		return CMD_RET_FAILURE;
+	parse_byte_string(argv[2], usage_auth, NULL);
+
+	err = tpm_get_pub_key_oiap(key_handle, usage_auth,
+			pub_key_buffer, &pub_key_len);
+	if (!err) {
+		printf("dump of received pub key structure:\n");
+		print_byte_string(pub_key_buffer, pub_key_len);
+	}
+	return convert_return_code(err);
+}
+
+TPM_COMMAND_NO_ARG(tpm_end_oiap)
+
+#endif /* CONFIG_TPM_AUTH_SESSIONS */
+
 #define MAKE_TPM_CMD_ENTRY(cmd) \
 	U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
 
@@ -590,6 +656,16 @@  static cmd_tbl_t tpm_commands[] = {
 			do_tpm_nv_read, "", ""),
 	U_BOOT_CMD_MKENT(nv_write, 0, 1,
 			do_tpm_nv_write, "", ""),
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+	U_BOOT_CMD_MKENT(oiap, 0, 1,
+			do_tpm_oiap, "", ""),
+	U_BOOT_CMD_MKENT(end_oiap, 0, 1,
+			do_tpm_end_oiap, "", ""),
+	U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1,
+			do_tpm_load_key2_oiap, "", ""),
+	U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1,
+			do_tpm_get_pub_key_oiap, "", ""),
+#endif /* CONFIG_TPM_AUTH_SESSIONS */
 };
 
 static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@@ -638,6 +714,16 @@  U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
 "  get_capability cap_area sub_cap addr count\n"
 "    - Read <count> bytes of TPM capability indexed by <cap_area> and\n"
 "      <sub_cap> to memory address <addr>.\n"
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+"Storage functions\n"
+"  loadkey2_oiap parent_handle key_addr key_len usage_auth\n"
+"    - loads a key data from memory address <key_addr>, <key_len> bytes\n"
+"      into TPM using the parent key <parent_handle> with authorization\n"
+"      <usage_auth> (20 bytes hex string).\n"
+"  get_pub_key_oiap key_handle usage_auth\n"
+"    - get the public key portion of a loaded key <key_handle> using\n"
+"      authorization <usage auth> (20 bytes hex string)\n"
+#endif /* CONFIG_TPM_AUTH_SESSIONS */
 "Endorsement Key Handling Commands:\n"
 "  read_pubek addr count\n"
 "    - Read <count> bytes of the public endorsement key to memory\n"
@@ -648,6 +734,13 @@  U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
 "      <digest_hex_string>\n"
 "  pcr_read index addr count\n"
 "    - Read <count> bytes from PCR <index> to memory address <addr>.\n"
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+"Authorization Sessions\n"
+"  oiap\n"
+"    - setup an OIAP session\n"
+"  end_oiap\n"
+"    - terminates an active OIAP session\n"
+#endif /* CONFIG_TPM_AUTH_SESSIONS */
 "Non-volatile Storage Commands:\n"
 "  nv_define_space index permission size\n"
 "    - Establish a space at index <index> with <permission> of <size> bytes.\n"
diff --git a/include/tpm.h b/include/tpm.h
index 7219b73..5e9f832 100644
--- a/include/tpm.h
+++ b/include/tpm.h
@@ -1,5 +1,6 @@ 
 /*
  * Copyright (c) 2013 The Chromium OS Authors.
+ * Coypright (c) 2013 Guntermann & Drunck GmbH
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -54,6 +55,120 @@  enum tpm_nv_index {
 };
 
 /**
+ * TPM return codes as defined in the TCG Main specification
+ * (TPM Main Part 2 Structures; Specification version 1.2)
+ */
+enum tpm_return_code {
+	TPM_BASE	= 0x00000000,
+	TPM_NON_FATAL	= 0x00000800,
+	TPM_SUCCESS	= TPM_BASE,
+	/* TPM-defined fatal error codes */
+	TPM_AUTHFAIL			= TPM_BASE +  1,
+	TPM_BADINDEX			= TPM_BASE +  2,
+	TPM_BAD_PARAMETER		= TPM_BASE +  3,
+	TPM_AUDITFAILURE		= TPM_BASE +  4,
+	TPM_CLEAR_DISABLED		= TPM_BASE +  5,
+	TPM_DEACTIVATED			= TPM_BASE +  6,
+	TPM_DISABLED			= TPM_BASE +  7,
+	TPM_DISABLED_CMD		= TPM_BASE +  8,
+	TPM_FAIL			= TPM_BASE +  9,
+	TPM_BAD_ORDINAL			= TPM_BASE + 10,
+	TPM_INSTALL_DISABLED		= TPM_BASE + 11,
+	TPM_INVALID_KEYHANDLE		= TPM_BASE + 12,
+	TPM_KEYNOTFOUND			= TPM_BASE + 13,
+	TPM_INAPPROPRIATE_ENC		= TPM_BASE + 14,
+	TPM_MIGRATE_FAIL		= TPM_BASE + 15,
+	TPM_INVALID_PCR_INFO		= TPM_BASE + 16,
+	TPM_NOSPACE			= TPM_BASE + 17,
+	TPM_NOSRK			= TPM_BASE + 18,
+	TPM_NOTSEALED_BLOB		= TPM_BASE + 19,
+	TPM_OWNER_SET			= TPM_BASE + 20,
+	TPM_RESOURCES			= TPM_BASE + 21,
+	TPM_SHORTRANDOM			= TPM_BASE + 22,
+	TPM_SIZE			= TPM_BASE + 23,
+	TPM_WRONGPCRVAL			= TPM_BASE + 24,
+	TPM_BAD_PARAM_SIZE		= TPM_BASE + 25,
+	TPM_SHA_THREAD			= TPM_BASE + 26,
+	TPM_SHA_ERROR			= TPM_BASE + 27,
+	TPM_FAILEDSELFTEST		= TPM_BASE + 28,
+	TPM_AUTH2FAIL			= TPM_BASE + 29,
+	TPM_BADTAG			= TPM_BASE + 30,
+	TPM_IOERROR			= TPM_BASE + 31,
+	TPM_ENCRYPT_ERROR		= TPM_BASE + 32,
+	TPM_DECRYPT_ERROR		= TPM_BASE + 33,
+	TPM_INVALID_AUTHHANDLE		= TPM_BASE + 34,
+	TPM_NO_ENDORSEMENT		= TPM_BASE + 35,
+	TPM_INVALID_KEYUSAGE		= TPM_BASE + 36,
+	TPM_WRONG_ENTITYTYPE		= TPM_BASE + 37,
+	TPM_INVALID_POSTINIT		= TPM_BASE + 38,
+	TPM_INAPPROPRIATE_SIG		= TPM_BASE + 39,
+	TPM_BAD_KEY_PROPERTY		= TPM_BASE + 40,
+	TPM_BAD_MIGRATION		= TPM_BASE + 41,
+	TPM_BAD_SCHEME			= TPM_BASE + 42,
+	TPM_BAD_DATASIZE		= TPM_BASE + 43,
+	TPM_BAD_MODE			= TPM_BASE + 44,
+	TPM_BAD_PRESENCE		= TPM_BASE + 45,
+	TPM_BAD_VERSION			= TPM_BASE + 46,
+	TPM_NO_WRAP_TRANSPORT		= TPM_BASE + 47,
+	TPM_AUDITFAIL_UNSUCCESSFUL	= TPM_BASE + 48,
+	TPM_AUDITFAIL_SUCCESSFUL	= TPM_BASE + 49,
+	TPM_NOTRESETABLE		= TPM_BASE + 50,
+	TPM_NOTLOCAL			= TPM_BASE + 51,
+	TPM_BAD_TYPE			= TPM_BASE + 52,
+	TPM_INVALID_RESOURCE		= TPM_BASE + 53,
+	TPM_NOTFIPS			= TPM_BASE + 54,
+	TPM_INVALID_FAMILY		= TPM_BASE + 55,
+	TPM_NO_NV_PERMISSION		= TPM_BASE + 56,
+	TPM_REQUIRES_SIGN		= TPM_BASE + 57,
+	TPM_KEY_NOTSUPPORTED		= TPM_BASE + 58,
+	TPM_AUTH_CONFLICT		= TPM_BASE + 59,
+	TPM_AREA_LOCKED			= TPM_BASE + 60,
+	TPM_BAD_LOCALITY		= TPM_BASE + 61,
+	TPM_READ_ONLY			= TPM_BASE + 62,
+	TPM_PER_NOWRITE			= TPM_BASE + 63,
+	TPM_FAMILY_COUNT		= TPM_BASE + 64,
+	TPM_WRITE_LOCKED		= TPM_BASE + 65,
+	TPM_BAD_ATTRIBUTES		= TPM_BASE + 66,
+	TPM_INVALID_STRUCTURE		= TPM_BASE + 67,
+	TPM_KEY_OWNER_CONTROL		= TPM_BASE + 68,
+	TPM_BAD_COUNTER			= TPM_BASE + 69,
+	TPM_NOT_FULLWRITE		= TPM_BASE + 70,
+	TPM_CONTEXT_GAP			= TPM_BASE + 71,
+	TPM_MAXNVWRITES			= TPM_BASE + 72,
+	TPM_NOOPERATOR			= TPM_BASE + 73,
+	TPM_RESOURCEMISSING		= TPM_BASE + 74,
+	TPM_DELEGATE_LOCK		= TPM_BASE + 75,
+	TPM_DELEGATE_FAMILY		= TPM_BASE + 76,
+	TPM_DELEGATE_ADMIN		= TPM_BASE + 77,
+	TPM_TRANSPORT_NOTEXCLUSIVE	= TPM_BASE + 78,
+	TPM_OWNER_CONTROL		= TPM_BASE + 79,
+	TPM_DAA_RESOURCES		= TPM_BASE + 80,
+	TPM_DAA_INPUT_DATA0		= TPM_BASE + 81,
+	TPM_DAA_INPUT_DATA1		= TPM_BASE + 82,
+	TPM_DAA_ISSUER_SETTINGS		= TPM_BASE + 83,
+	TPM_DAA_TPM_SETTINGS		= TPM_BASE + 84,
+	TPM_DAA_STAGE			= TPM_BASE + 85,
+	TPM_DAA_ISSUER_VALIDITY		= TPM_BASE + 86,
+	TPM_DAA_WRONG_W			= TPM_BASE + 87,
+	TPM_BAD_HANDLE			= TPM_BASE + 88,
+	TPM_BAD_DELEGATE		= TPM_BASE + 89,
+	TPM_BADCONTEXT			= TPM_BASE + 90,
+	TPM_TOOMANYCONTEXTS		= TPM_BASE + 91,
+	TPM_MA_TICKET_SIGNATURE		= TPM_BASE + 92,
+	TPM_MA_DESTINATION		= TPM_BASE + 93,
+	TPM_MA_SOURCE			= TPM_BASE + 94,
+	TPM_MA_AUTHORITY		= TPM_BASE + 95,
+	TPM_PERMANENTEK			= TPM_BASE + 97,
+	TPM_BAD_SIGNATURE		= TPM_BASE + 98,
+	TPM_NOCONTEXTSPACE		= TPM_BASE + 99,
+	/* TPM-defined non-fatal errors */
+	TPM_RETRY		= TPM_BASE + TPM_NON_FATAL,
+	TPM_NEEDS_SELFTEST	= TPM_BASE + TPM_NON_FATAL + 1,
+	TPM_DOING_SELFTEST	= TPM_BASE + TPM_NON_FATAL + 2,
+	TPM_DEFEND_LOCK_RUNNING	= TPM_BASE + TPM_NON_FATAL + 3,
+};
+
+/**
  * Initialize TPM device.  It must be called before any TPM commands.
  *
  * @return 0 on success, non-0 on error.
@@ -201,4 +316,63 @@  uint32_t tpm_physical_set_deactivated(uint8_t state);
 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
 		void *cap, size_t count);
 
+/**
+ * Issue a TPM_FlushSpecific command for a AUTH ressource.
+ *
+ * @param auth_handle	handle of the auth session
+ * @return return code of the operation
+ */
+uint32_t tpm_terminate_auth_session(uint32_t auth_handle);
+
+/**
+ * Issue a TPM_OIAP command to setup an object independant authorization
+ * session.
+ * Information about the session is stored internally.
+ * If there was already an OIAP session active it is terminated and a new
+ * session is set up.
+ *
+ * @param auth_handle	pointer to the (new) auth handle or NULL.
+ * @return return code of the operation
+ */
+uint32_t tpm_oiap(uint32_t *auth_handle);
+
+/**
+ * Ends an active OIAP session.
+ *
+ * @return return code of the operation
+ */
+uint32_t tpm_end_oiap(void);
+
+/**
+ * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating
+ * the usage of the parent key.
+ *
+ * @param parent_handle	handle of the parent key.
+ * @param key		pointer to the key structure (TPM_KEY or TPM_KEY12).
+ * @param key_length	size of the key structure
+ * @param parent_key_usage_auth	usage auth for the parent key
+ * @param key_handle	pointer to the key handle
+ * @return return code of the operation
+ */
+uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
+		const void *key, size_t key_length,
+		const void *parent_key_usage_auth,
+		uint32_t *key_handle);
+
+/**
+ * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for
+ * authenticating the usage of the key.
+ *
+ * @param key_handle	handle of the key
+ * @param usage_auth	usage auth for the key
+ * @param pubkey	pointer to the pub key buffer; may be NULL if the pubkey
+ *			should not be stored.
+ * @param pubkey_len	pointer to the pub key buffer len. On entry: the size of
+ *			the provided pubkey buffer. On successful exit: the size
+ *			of the stored TPM_PUBKEY structure (iff pubkey != NULL).
+ * @return return code of the operation
+ */
+uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
+		void *pubkey, size_t *pubkey_len);
+
 #endif /* __TPM_H */
diff --git a/lib/tpm.c b/lib/tpm.c
index 42c9bea..87bf188 100644
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -1,5 +1,6 @@ 
 /*
  * Copyright (c) 2013 The Chromium OS Authors.
+ * Coypright (c) 2013 Guntermann & Drunck GmbH
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -22,6 +23,7 @@ 
 
 #include <common.h>
 #include <stdarg.h>
+#include <sha1.h>
 #include <tpm.h>
 #include <asm/unaligned.h>
 
@@ -35,8 +37,31 @@  enum {
 	TPM_REQUEST_HEADER_LENGTH	= 10,
 	TPM_RESPONSE_HEADER_LENGTH	= 10,
 	PCR_DIGEST_LENGTH		= 20,
+	DIGEST_LENGTH			= 20,
+	TPM_REQUEST_AUTH_LENGTH		= 45,
+	TPM_RESPONSE_AUTH_LENGTH	= 41,
+	/* some max lengths, valid for RSA keys <= 2048 bits */
+	TPM_KEY12_MAX_LENGTH		= 618,
+	TPM_PUBKEY_MAX_LENGTH		= 288,
 };
 
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+
+#ifndef CONFIG_SHA1
+#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
+#endif /* !CONFIG_SHA1 */
+
+struct session_data {
+	int		valid;
+	uint32_t	handle;
+	uint8_t		nonce_even[DIGEST_LENGTH];
+	uint8_t		nonce_odd[DIGEST_LENGTH];
+};
+
+static struct session_data oiap_session = {0, };
+
+#endif /* CONFIG_TPM_AUTH_SESSIONS */
+
 /**
  * Pack data into a byte string.  The data types are specified in
  * the format string: 'b' means unsigned byte, 'w' unsigned word,
@@ -235,7 +260,7 @@  static uint32_t tpm_sendrecv_command(const void *command,
 			response, &response_length);
 	if (err)
 		return TPM_LIB_ERROR;
-	if (response)
+	if (size_ptr)
 		*size_ptr = response_length;
 
 	return tpm_return_code(response);
@@ -579,3 +604,324 @@  uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
 
 	return 0;
 }
+
+#ifdef CONFIG_TPM_AUTH_SESSIONS
+
+/**
+ * Fill an authentication block in a request.
+ * This func can create the first as well as the second auth block (for
+ * double authorized commands).
+ *
+ * @param request	pointer to the request (w/ uninitialised auth data)
+ * @param request_len0	length of the request without auth data
+ * @param handles_len	length of the handles area in request
+ * @param auth_session	pointer to the (valid) auth session to be used
+ * @param request_auth	pointer to the auth block of the request to be filled
+ * @param auth		authentication data (HMAC key)
+ */
+static uint32_t create_request_auth(const void *request, size_t request_len0,
+	size_t handles_len,
+	struct session_data *auth_session,
+	void *request_auth, const void *auth)
+{
+	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
+	sha1_context hash_ctx;
+	const size_t command_code_offset = 6;
+	const size_t auth_nonce_odd_offset = 4;
+	const size_t auth_continue_offset = 24;
+	const size_t auth_auth_offset = 25;
+
+	if (!auth_session || !auth_session->valid)
+		return TPM_LIB_ERROR;
+
+	sha1_starts(&hash_ctx);
+	sha1_update(&hash_ctx, request + command_code_offset, 4);
+	if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
+		sha1_update(&hash_ctx,
+			request + TPM_REQUEST_HEADER_LENGTH + handles_len,
+			request_len0 - TPM_REQUEST_HEADER_LENGTH - handles_len);
+	sha1_finish(&hash_ctx, hmac_data);
+
+	sha1_starts(&hash_ctx);
+	sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
+	sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
+	sha1_finish(&hash_ctx, auth_session->nonce_odd);
+
+	if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
+			0, auth_session->handle,
+			auth_nonce_odd_offset, auth_session->nonce_odd,
+			DIGEST_LENGTH,
+			auth_continue_offset, 1))
+		return TPM_LIB_ERROR;
+	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
+				DIGEST_LENGTH,
+				auth_session->nonce_even,
+				DIGEST_LENGTH,
+				2 * DIGEST_LENGTH,
+				request_auth + auth_nonce_odd_offset,
+				DIGEST_LENGTH + 1))
+		return TPM_LIB_ERROR;
+	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
+		request_auth + auth_auth_offset);
+
+	return TPM_SUCCESS;
+}
+
+/**
+ * Verify an authentication block in a response.
+ * Since this func updates the nonce_even in the session data it has to be
+ * called when receiving a succesfull AUTH response.
+ * This func can verify the first as well as the second auth block (for
+ * double authorized commands).
+ *
+ * @param command_code	command code of the request
+ * @param response	pointer to the request (w/ uninitialised auth data)
+ * @param handles_len	length of the handles area in response
+ * @param auth_session	pointer to the (valid) auth session to be used
+ * @param response_auth	pointer to the auth block of the response to be verified
+ * @param auth		authentication data (HMAC key)
+ */
+static uint32_t verify_response_auth(uint32_t command_code,
+	const void *response, size_t response_len0,
+	size_t handles_len,
+	struct session_data *auth_session,
+	const void *response_auth, const void *auth)
+{
+	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
+	uint8_t computed_auth[DIGEST_LENGTH];
+	sha1_context hash_ctx;
+	const size_t return_code_offset = 6;
+	const size_t auth_continue_offset = 20;
+	const size_t auth_auth_offset = 21;
+	uint8_t auth_continue;
+
+	if (!auth_session || !auth_session->valid)
+		return TPM_AUTHFAIL;
+	if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
+				0, command_code))
+		return TPM_LIB_ERROR;
+	if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
+		return TPM_LIB_ERROR;
+
+	sha1_starts(&hash_ctx);
+	sha1_update(&hash_ctx, response + return_code_offset, 4);
+	sha1_update(&hash_ctx, hmac_data, 4);
+	if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
+		sha1_update(&hash_ctx,
+			response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
+			response_len0 - TPM_RESPONSE_HEADER_LENGTH
+			- handles_len);
+	sha1_finish(&hash_ctx, hmac_data);
+
+	memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
+	auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
+	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
+				DIGEST_LENGTH,
+				response_auth,
+				DIGEST_LENGTH,
+				2 * DIGEST_LENGTH,
+				auth_session->nonce_odd,
+				DIGEST_LENGTH,
+				3 * DIGEST_LENGTH,
+				auth_continue))
+		return TPM_LIB_ERROR;
+
+	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
+		computed_auth);
+
+	if (memcmp(computed_auth, response_auth + auth_auth_offset,
+			DIGEST_LENGTH))
+		return TPM_AUTHFAIL;
+
+	return TPM_SUCCESS;
+}
+
+
+uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
+{
+	const uint8_t command[18] = {
+		0x00, 0xc1,		/* TPM_TAG */
+		0x00, 0x00, 0x00, 0x00,	/* parameter size */
+		0x00, 0x00, 0x00, 0xba,	/* TPM_COMMAND_CODE */
+		0x00, 0x00, 0x00, 0x00,	/* TPM_HANDLE */
+		0x00, 0x00, 0x00, 0x02,	/* TPM_RESSOURCE_TYPE */
+	};
+	const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
+	uint8_t request[COMMAND_BUFFER_SIZE];
+
+	if (pack_byte_string(request, sizeof(request), "sd",
+			0, command, sizeof(command),
+			req_handle_offset, auth_handle))
+		return TPM_LIB_ERROR;
+	if (oiap_session.valid && oiap_session.handle == auth_handle)
+		oiap_session.valid = 0;
+
+	return tpm_sendrecv_command(request, NULL, NULL);
+}
+
+uint32_t tpm_end_oiap(void)
+{
+	uint32_t err = TPM_SUCCESS;
+	if (oiap_session.valid)
+		err = tpm_terminate_auth_session(oiap_session.handle);
+	return err;
+}
+
+uint32_t tpm_oiap(uint32_t *auth_handle)
+{
+	const uint8_t command[10] = {
+		0x00, 0xc1,		/* TPM_TAG */
+		0x00, 0x00, 0x00, 0x0a,	/* parameter size */
+		0x00, 0x00, 0x00, 0x0a,	/* TPM_COMMAND_CODE */
+	};
+	const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
+	const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
+	uint8_t response[COMMAND_BUFFER_SIZE];
+	size_t response_length = sizeof(response);
+	uint32_t err;
+
+	if (oiap_session.valid)
+		tpm_terminate_auth_session(oiap_session.handle);
+
+	err = tpm_sendrecv_command(command, response, &response_length);
+	if (err)
+		return err;
+	if (unpack_byte_string(response, response_length, "ds",
+			res_auth_handle_offset, &oiap_session.handle,
+			res_nonce_even_offset, &oiap_session.nonce_even,
+			(uint32_t)DIGEST_LENGTH))
+		return TPM_LIB_ERROR;
+	oiap_session.valid = 1;
+	if (auth_handle)
+		*auth_handle = oiap_session.handle;
+	return 0;
+}
+
+uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
+		const void *key, size_t key_length,
+		const void *parent_key_usage_auth,
+		uint32_t *key_handle)
+{
+	const uint8_t command[14] = {
+		0x00, 0xc2,		/* TPM_TAG */
+		0x00, 0x00, 0x00, 0x00,	/* parameter size */
+		0x00, 0x00, 0x00, 0x41,	/* TPM_COMMAND_CODE */
+		0x00, 0x00, 0x00, 0x00,	/* parent handle */
+	};
+	const size_t req_size_offset = 2;
+	const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
+	const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
+	const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
+	uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
+			+ TPM_REQUEST_AUTH_LENGTH];
+	uint8_t response[COMMAND_BUFFER_SIZE];
+	size_t response_length = sizeof(response);
+	uint32_t err;
+
+	if (!oiap_session.valid) {
+		err = tpm_oiap(NULL);
+		if (err)
+			return err;
+	}
+	if (pack_byte_string(request, sizeof(request), "sdds",
+			0, command, sizeof(command),
+			req_size_offset,
+			sizeof(command) + key_length + TPM_REQUEST_AUTH_LENGTH,
+			req_parent_handle_offset, parent_handle,
+			req_key_offset, key, key_length
+		))
+		return TPM_LIB_ERROR;
+
+	err = create_request_auth(request, sizeof(command) + key_length, 4,
+			&oiap_session,
+			request + sizeof(command) + key_length,
+			parent_key_usage_auth);
+	if (err)
+		return err;
+	err = tpm_sendrecv_command(request, response, &response_length);
+	if (err) {
+		if (err == TPM_AUTHFAIL)
+			oiap_session.valid = 0;
+		return err;
+	}
+
+	err = verify_response_auth(0x00000041, response,
+			response_length - TPM_RESPONSE_AUTH_LENGTH,
+			4, &oiap_session,
+			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
+			parent_key_usage_auth);
+	if (err)
+		return err;
+
+	if (key_handle) {
+		if (unpack_byte_string(response, response_length, "d",
+				res_handle_offset, key_handle))
+			return TPM_LIB_ERROR;
+	}
+
+	return 0;
+}
+
+uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
+			void *pubkey, size_t *pubkey_len)
+{
+	const uint8_t command[14] = {
+		0x00, 0xc2,		/* TPM_TAG */
+		0x00, 0x00, 0x00, 0x00,	/* parameter size */
+		0x00, 0x00, 0x00, 0x21,	/* TPM_COMMAND_CODE */
+		0x00, 0x00, 0x00, 0x00,	/* key handle */
+	};
+	const size_t req_size_offset = 2;
+	const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
+	const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
+	uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
+	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
+			+ TPM_RESPONSE_AUTH_LENGTH];
+	size_t response_length = sizeof(response);
+	uint32_t err;
+
+	if (!oiap_session.valid) {
+		err = tpm_oiap(NULL);
+		if (err)
+			return err;
+	}
+	if (pack_byte_string(request, sizeof(request), "sdd",
+			0, command, sizeof(command),
+			req_size_offset,
+			(uint32_t)(sizeof(command) + TPM_REQUEST_AUTH_LENGTH),
+			req_key_handle_offset, key_handle
+		))
+		return TPM_LIB_ERROR;
+	err = create_request_auth(request, sizeof(command), 4, &oiap_session,
+			request + sizeof(command), usage_auth);
+	if (err)
+		return err;
+	err = tpm_sendrecv_command(request, response, &response_length);
+	if (err) {
+		if (err == TPM_AUTHFAIL)
+			oiap_session.valid = 0;
+		return err;
+	}
+	err = verify_response_auth(0x00000021, response,
+			response_length - TPM_RESPONSE_AUTH_LENGTH,
+			0, &oiap_session,
+			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
+			usage_auth);
+	if (err)
+		return err;
+
+	if (pubkey) {
+		if ((response_length - TPM_RESPONSE_HEADER_LENGTH
+			- TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
+			return TPM_LIB_ERROR;
+		*pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
+			- TPM_RESPONSE_AUTH_LENGTH;
+		memcpy(pubkey, response + res_pubkey_offset,
+			response_length - TPM_RESPONSE_HEADER_LENGTH
+				- TPM_RESPONSE_AUTH_LENGTH);
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_TPM_AUTH_SESSIONS */