uboot/lib/tpm.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 The Chromium OS Authors.
   3 * Coypright (c) 2013 Guntermann & Drunck GmbH
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <stdarg.h>
  10#include <u-boot/sha1.h>
  11#include <tpm.h>
  12#include <asm/unaligned.h>
  13
  14/* Internal error of TPM command library */
  15#define TPM_LIB_ERROR   ((uint32_t)~0u)
  16
  17/* Useful constants */
  18enum {
  19        COMMAND_BUFFER_SIZE             = 256,
  20        TPM_PUBEK_SIZE                  = 256,
  21        TPM_REQUEST_HEADER_LENGTH       = 10,
  22        TPM_RESPONSE_HEADER_LENGTH      = 10,
  23        PCR_DIGEST_LENGTH               = 20,
  24        DIGEST_LENGTH                   = 20,
  25        TPM_REQUEST_AUTH_LENGTH         = 45,
  26        TPM_RESPONSE_AUTH_LENGTH        = 41,
  27        /* some max lengths, valid for RSA keys <= 2048 bits */
  28        TPM_KEY12_MAX_LENGTH            = 618,
  29        TPM_PUBKEY_MAX_LENGTH           = 288,
  30};
  31
  32#ifdef CONFIG_TPM_AUTH_SESSIONS
  33
  34#ifndef CONFIG_SHA1
  35#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
  36#endif /* !CONFIG_SHA1 */
  37
  38struct session_data {
  39        int             valid;
  40        uint32_t        handle;
  41        uint8_t         nonce_even[DIGEST_LENGTH];
  42        uint8_t         nonce_odd[DIGEST_LENGTH];
  43};
  44
  45static struct session_data oiap_session = {0, };
  46
  47#endif /* CONFIG_TPM_AUTH_SESSIONS */
  48
  49/**
  50 * Pack data into a byte string.  The data types are specified in
  51 * the format string: 'b' means unsigned byte, 'w' unsigned word,
  52 * 'd' unsigned double word, and 's' byte string.  The data are a
  53 * series of offsets and values (for type byte string there are also
  54 * lengths).  The data values are packed into the byte string
  55 * sequentially, and so a latter value could over-write a former
  56 * value.
  57 *
  58 * @param str           output string
  59 * @param size          size of output string
  60 * @param format        format string
  61 * @param ...           data points
  62 * @return 0 on success, non-0 on error
  63 */
  64int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
  65{
  66        va_list args;
  67        size_t offset = 0, length = 0;
  68        uint8_t *data = NULL;
  69        uint32_t value = 0;
  70
  71        va_start(args, format);
  72        for (; *format; format++) {
  73                switch (*format) {
  74                case 'b':
  75                        offset = va_arg(args, size_t);
  76                        value = va_arg(args, int);
  77                        length = 1;
  78                        break;
  79                case 'w':
  80                        offset = va_arg(args, size_t);
  81                        value = va_arg(args, int);
  82                        length = 2;
  83                        break;
  84                case 'd':
  85                        offset = va_arg(args, size_t);
  86                        value = va_arg(args, uint32_t);
  87                        length = 4;
  88                        break;
  89                case 's':
  90                        offset = va_arg(args, size_t);
  91                        data = va_arg(args, uint8_t *);
  92                        length = va_arg(args, uint32_t);
  93                        break;
  94                default:
  95                        debug("Couldn't recognize format string\n");
  96                        return -1;
  97                }
  98
  99                if (offset + length > size)
 100                        return -1;
 101
 102                switch (*format) {
 103                case 'b':
 104                        str[offset] = value;
 105                        break;
 106                case 'w':
 107                        put_unaligned_be16(value, str + offset);
 108                        break;
 109                case 'd':
 110                        put_unaligned_be32(value, str + offset);
 111                        break;
 112                case 's':
 113                        memcpy(str + offset, data, length);
 114                        break;
 115                }
 116        }
 117        va_end(args);
 118
 119        return 0;
 120}
 121
 122/**
 123 * Unpack data from a byte string.  The data types are specified in
 124 * the format string: 'b' means unsigned byte, 'w' unsigned word,
 125 * 'd' unsigned double word, and 's' byte string.  The data are a
 126 * series of offsets and pointers (for type byte string there are also
 127 * lengths).
 128 *
 129 * @param str           output string
 130 * @param size          size of output string
 131 * @param format        format string
 132 * @param ...           data points
 133 * @return 0 on success, non-0 on error
 134 */
 135int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
 136{
 137        va_list args;
 138        size_t offset = 0, length = 0;
 139        uint8_t *ptr8 = NULL;
 140        uint16_t *ptr16 = NULL;
 141        uint32_t *ptr32 = NULL;
 142
 143        va_start(args, format);
 144        for (; *format; format++) {
 145                switch (*format) {
 146                case 'b':
 147                        offset = va_arg(args, size_t);
 148                        ptr8 = va_arg(args, uint8_t *);
 149                        length = 1;
 150                        break;
 151                case 'w':
 152                        offset = va_arg(args, size_t);
 153                        ptr16 = va_arg(args, uint16_t *);
 154                        length = 2;
 155                        break;
 156                case 'd':
 157                        offset = va_arg(args, size_t);
 158                        ptr32 = va_arg(args, uint32_t *);
 159                        length = 4;
 160                        break;
 161                case 's':
 162                        offset = va_arg(args, size_t);
 163                        ptr8 = va_arg(args, uint8_t *);
 164                        length = va_arg(args, uint32_t);
 165                        break;
 166                default:
 167                        debug("Couldn't recognize format string\n");
 168                        return -1;
 169                }
 170
 171                if (offset + length > size)
 172                        return -1;
 173
 174                switch (*format) {
 175                case 'b':
 176                        *ptr8 = str[offset];
 177                        break;
 178                case 'w':
 179                        *ptr16 = get_unaligned_be16(str + offset);
 180                        break;
 181                case 'd':
 182                        *ptr32 = get_unaligned_be32(str + offset);
 183                        break;
 184                case 's':
 185                        memcpy(ptr8, str + offset, length);
 186                        break;
 187                }
 188        }
 189        va_end(args);
 190
 191        return 0;
 192}
 193
 194/**
 195 * Get TPM command size.
 196 *
 197 * @param command       byte string of TPM command
 198 * @return command size of the TPM command
 199 */
 200static uint32_t tpm_command_size(const void *command)
 201{
 202        const size_t command_size_offset = 2;
 203        return get_unaligned_be32(command + command_size_offset);
 204}
 205
 206/**
 207 * Get TPM response return code, which is one of TPM_RESULT values.
 208 *
 209 * @param response      byte string of TPM response
 210 * @return return code of the TPM response
 211 */
 212static uint32_t tpm_return_code(const void *response)
 213{
 214        const size_t return_code_offset = 6;
 215        return get_unaligned_be32(response + return_code_offset);
 216}
 217
 218/**
 219 * Send a TPM command and return response's return code, and optionally
 220 * return response to caller.
 221 *
 222 * @param command       byte string of TPM command
 223 * @param response      output buffer for TPM response, or NULL if the
 224 *                      caller does not care about it
 225 * @param size_ptr      output buffer size (input parameter) and TPM
 226 *                      response length (output parameter); this parameter
 227 *                      is a bidirectional
 228 * @return return code of the TPM response
 229 */
 230static uint32_t tpm_sendrecv_command(const void *command,
 231                void *response, size_t *size_ptr)
 232{
 233        uint8_t response_buffer[COMMAND_BUFFER_SIZE];
 234        size_t response_length;
 235        uint32_t err;
 236
 237        if (response) {
 238                response_length = *size_ptr;
 239        } else {
 240                response = response_buffer;
 241                response_length = sizeof(response_buffer);
 242        }
 243        err = tis_sendrecv(command, tpm_command_size(command),
 244                        response, &response_length);
 245        if (err)
 246                return TPM_LIB_ERROR;
 247        if (size_ptr)
 248                *size_ptr = response_length;
 249
 250        return tpm_return_code(response);
 251}
 252
 253uint32_t tpm_init(void)
 254{
 255        uint32_t err;
 256
 257        err = tis_init();
 258        if (err)
 259                return err;
 260
 261        return tis_open();
 262}
 263
 264uint32_t tpm_startup(enum tpm_startup_type mode)
 265{
 266        const uint8_t command[12] = {
 267                0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
 268        };
 269        const size_t mode_offset = 10;
 270        uint8_t buf[COMMAND_BUFFER_SIZE];
 271
 272        if (pack_byte_string(buf, sizeof(buf), "sw",
 273                                0, command, sizeof(command),
 274                                mode_offset, mode))
 275                return TPM_LIB_ERROR;
 276
 277        return tpm_sendrecv_command(buf, NULL, NULL);
 278}
 279
 280uint32_t tpm_self_test_full(void)
 281{
 282        const uint8_t command[10] = {
 283                0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
 284        };
 285        return tpm_sendrecv_command(command, NULL, NULL);
 286}
 287
 288uint32_t tpm_continue_self_test(void)
 289{
 290        const uint8_t command[10] = {
 291                0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
 292        };
 293        return tpm_sendrecv_command(command, NULL, NULL);
 294}
 295
 296uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
 297{
 298        const uint8_t command[101] = {
 299                0x0, 0xc1,              /* TPM_TAG */
 300                0x0, 0x0, 0x0, 0x65,    /* parameter size */
 301                0x0, 0x0, 0x0, 0xcc,    /* TPM_COMMAND_CODE */
 302                /* TPM_NV_DATA_PUBLIC->... */
 303                0x0, 0x18,              /* ...->TPM_STRUCTURE_TAG */
 304                0, 0, 0, 0,             /* ...->TPM_NV_INDEX */
 305                /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
 306                0x0, 0x3,
 307                0, 0, 0,
 308                0x1f,
 309                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 310                /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
 311                0x0, 0x3,
 312                0, 0, 0,
 313                0x1f,
 314                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 315                /* TPM_NV_ATTRIBUTES->... */
 316                0x0, 0x17,              /* ...->TPM_STRUCTURE_TAG */
 317                0, 0, 0, 0,             /* ...->attributes */
 318                /* End of TPM_NV_ATTRIBUTES */
 319                0,                      /* bReadSTClear */
 320                0,                      /* bWriteSTClear */
 321                0,                      /* bWriteDefine */
 322                0, 0, 0, 0,             /* size */
 323        };
 324        const size_t index_offset = 12;
 325        const size_t perm_offset = 70;
 326        const size_t size_offset = 77;
 327        uint8_t buf[COMMAND_BUFFER_SIZE];
 328
 329        if (pack_byte_string(buf, sizeof(buf), "sddd",
 330                                0, command, sizeof(command),
 331                                index_offset, index,
 332                                perm_offset, perm,
 333                                size_offset, size))
 334                return TPM_LIB_ERROR;
 335
 336        return tpm_sendrecv_command(buf, NULL, NULL);
 337}
 338
 339uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
 340{
 341        const uint8_t command[22] = {
 342                0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
 343        };
 344        const size_t index_offset = 10;
 345        const size_t length_offset = 18;
 346        const size_t data_size_offset = 10;
 347        const size_t data_offset = 14;
 348        uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
 349        size_t response_length = sizeof(response);
 350        uint32_t data_size;
 351        uint32_t err;
 352
 353        if (pack_byte_string(buf, sizeof(buf), "sdd",
 354                                0, command, sizeof(command),
 355                                index_offset, index,
 356                                length_offset, count))
 357                return TPM_LIB_ERROR;
 358        err = tpm_sendrecv_command(buf, response, &response_length);
 359        if (err)
 360                return err;
 361        if (unpack_byte_string(response, response_length, "d",
 362                                data_size_offset, &data_size))
 363                return TPM_LIB_ERROR;
 364        if (data_size > count)
 365                return TPM_LIB_ERROR;
 366        if (unpack_byte_string(response, response_length, "s",
 367                                data_offset, data, data_size))
 368                return TPM_LIB_ERROR;
 369
 370        return 0;
 371}
 372
 373uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
 374{
 375        const uint8_t command[256] = {
 376                0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
 377        };
 378        const size_t command_size_offset = 2;
 379        const size_t index_offset = 10;
 380        const size_t length_offset = 18;
 381        const size_t data_offset = 22;
 382        const size_t write_info_size = 12;
 383        const uint32_t total_length =
 384                TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
 385        uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
 386        size_t response_length = sizeof(response);
 387        uint32_t err;
 388
 389        if (pack_byte_string(buf, sizeof(buf), "sddds",
 390                                0, command, sizeof(command),
 391                                command_size_offset, total_length,
 392                                index_offset, index,
 393                                length_offset, length,
 394                                data_offset, data, length))
 395                return TPM_LIB_ERROR;
 396        err = tpm_sendrecv_command(buf, response, &response_length);
 397        if (err)
 398                return err;
 399
 400        return 0;
 401}
 402
 403uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
 404{
 405        const uint8_t command[34] = {
 406                0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
 407        };
 408        const size_t index_offset = 10;
 409        const size_t in_digest_offset = 14;
 410        const size_t out_digest_offset = 10;
 411        uint8_t buf[COMMAND_BUFFER_SIZE];
 412        uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
 413        size_t response_length = sizeof(response);
 414        uint32_t err;
 415
 416        if (pack_byte_string(buf, sizeof(buf), "sds",
 417                                0, command, sizeof(command),
 418                                index_offset, index,
 419                                in_digest_offset, in_digest,
 420                                PCR_DIGEST_LENGTH))
 421                return TPM_LIB_ERROR;
 422        err = tpm_sendrecv_command(buf, response, &response_length);
 423        if (err)
 424                return err;
 425
 426        if (unpack_byte_string(response, response_length, "s",
 427                                out_digest_offset, out_digest,
 428                                PCR_DIGEST_LENGTH))
 429                return TPM_LIB_ERROR;
 430
 431        return 0;
 432}
 433
 434uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
 435{
 436        const uint8_t command[14] = {
 437                0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
 438        };
 439        const size_t index_offset = 10;
 440        const size_t out_digest_offset = 10;
 441        uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
 442        size_t response_length = sizeof(response);
 443        uint32_t err;
 444
 445        if (count < PCR_DIGEST_LENGTH)
 446                return TPM_LIB_ERROR;
 447
 448        if (pack_byte_string(buf, sizeof(buf), "sd",
 449                                0, command, sizeof(command),
 450                                index_offset, index))
 451                return TPM_LIB_ERROR;
 452        err = tpm_sendrecv_command(buf, response, &response_length);
 453        if (err)
 454                return err;
 455        if (unpack_byte_string(response, response_length, "s",
 456                                out_digest_offset, data, PCR_DIGEST_LENGTH))
 457                return TPM_LIB_ERROR;
 458
 459        return 0;
 460}
 461
 462uint32_t tpm_tsc_physical_presence(uint16_t presence)
 463{
 464        const uint8_t command[12] = {
 465                0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
 466        };
 467        const size_t presence_offset = 10;
 468        uint8_t buf[COMMAND_BUFFER_SIZE];
 469
 470        if (pack_byte_string(buf, sizeof(buf), "sw",
 471                                0, command, sizeof(command),
 472                                presence_offset, presence))
 473                return TPM_LIB_ERROR;
 474
 475        return tpm_sendrecv_command(buf, NULL, NULL);
 476}
 477
 478uint32_t tpm_read_pubek(void *data, size_t count)
 479{
 480        const uint8_t command[30] = {
 481                0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
 482        };
 483        const size_t response_size_offset = 2;
 484        const size_t data_offset = 10;
 485        const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
 486        uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
 487        size_t response_length = sizeof(response);
 488        uint32_t data_size;
 489        uint32_t err;
 490
 491        err = tpm_sendrecv_command(command, response, &response_length);
 492        if (err)
 493                return err;
 494        if (unpack_byte_string(response, response_length, "d",
 495                                response_size_offset, &data_size))
 496                return TPM_LIB_ERROR;
 497        if (data_size < header_and_checksum_size)
 498                return TPM_LIB_ERROR;
 499        data_size -= header_and_checksum_size;
 500        if (data_size > count)
 501                return TPM_LIB_ERROR;
 502        if (unpack_byte_string(response, response_length, "s",
 503                                data_offset, data, data_size))
 504                return TPM_LIB_ERROR;
 505
 506        return 0;
 507}
 508
 509uint32_t tpm_force_clear(void)
 510{
 511        const uint8_t command[10] = {
 512                0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
 513        };
 514
 515        return tpm_sendrecv_command(command, NULL, NULL);
 516}
 517
 518uint32_t tpm_physical_enable(void)
 519{
 520        const uint8_t command[10] = {
 521                0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
 522        };
 523
 524        return tpm_sendrecv_command(command, NULL, NULL);
 525}
 526
 527uint32_t tpm_physical_disable(void)
 528{
 529        const uint8_t command[10] = {
 530                0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
 531        };
 532
 533        return tpm_sendrecv_command(command, NULL, NULL);
 534}
 535
 536uint32_t tpm_physical_set_deactivated(uint8_t state)
 537{
 538        const uint8_t command[11] = {
 539                0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
 540        };
 541        const size_t state_offset = 10;
 542        uint8_t buf[COMMAND_BUFFER_SIZE];
 543
 544        if (pack_byte_string(buf, sizeof(buf), "sb",
 545                                0, command, sizeof(command),
 546                                state_offset, state))
 547                return TPM_LIB_ERROR;
 548
 549        return tpm_sendrecv_command(buf, NULL, NULL);
 550}
 551
 552uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
 553                void *cap, size_t count)
 554{
 555        const uint8_t command[22] = {
 556                0x0, 0xc1,              /* TPM_TAG */
 557                0x0, 0x0, 0x0, 0x16,    /* parameter size */
 558                0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
 559                0x0, 0x0, 0x0, 0x0,     /* TPM_CAPABILITY_AREA */
 560                0x0, 0x0, 0x0, 0x4,     /* subcap size */
 561                0x0, 0x0, 0x0, 0x0,     /* subcap value */
 562        };
 563        const size_t cap_area_offset = 10;
 564        const size_t sub_cap_offset = 18;
 565        const size_t cap_offset = 14;
 566        const size_t cap_size_offset = 10;
 567        uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
 568        size_t response_length = sizeof(response);
 569        uint32_t cap_size;
 570        uint32_t err;
 571
 572        if (pack_byte_string(buf, sizeof(buf), "sdd",
 573                                0, command, sizeof(command),
 574                                cap_area_offset, cap_area,
 575                                sub_cap_offset, sub_cap))
 576                return TPM_LIB_ERROR;
 577        err = tpm_sendrecv_command(buf, response, &response_length);
 578        if (err)
 579                return err;
 580        if (unpack_byte_string(response, response_length, "d",
 581                                cap_size_offset, &cap_size))
 582                return TPM_LIB_ERROR;
 583        if (cap_size > response_length || cap_size > count)
 584                return TPM_LIB_ERROR;
 585        if (unpack_byte_string(response, response_length, "s",
 586                                cap_offset, cap, cap_size))
 587                return TPM_LIB_ERROR;
 588
 589        return 0;
 590}
 591
 592#ifdef CONFIG_TPM_AUTH_SESSIONS
 593
 594/**
 595 * Fill an authentication block in a request.
 596 * This func can create the first as well as the second auth block (for
 597 * double authorized commands).
 598 *
 599 * @param request       pointer to the request (w/ uninitialised auth data)
 600 * @param request_len0  length of the request without auth data
 601 * @param handles_len   length of the handles area in request
 602 * @param auth_session  pointer to the (valid) auth session to be used
 603 * @param request_auth  pointer to the auth block of the request to be filled
 604 * @param auth          authentication data (HMAC key)
 605 */
 606static uint32_t create_request_auth(const void *request, size_t request_len0,
 607        size_t handles_len,
 608        struct session_data *auth_session,
 609        void *request_auth, const void *auth)
 610{
 611        uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
 612        sha1_context hash_ctx;
 613        const size_t command_code_offset = 6;
 614        const size_t auth_nonce_odd_offset = 4;
 615        const size_t auth_continue_offset = 24;
 616        const size_t auth_auth_offset = 25;
 617
 618        if (!auth_session || !auth_session->valid)
 619                return TPM_LIB_ERROR;
 620
 621        sha1_starts(&hash_ctx);
 622        sha1_update(&hash_ctx, request + command_code_offset, 4);
 623        if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
 624                sha1_update(&hash_ctx,
 625                            request + TPM_REQUEST_HEADER_LENGTH + handles_len,
 626                            request_len0 - TPM_REQUEST_HEADER_LENGTH
 627                            - handles_len);
 628        sha1_finish(&hash_ctx, hmac_data);
 629
 630        sha1_starts(&hash_ctx);
 631        sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
 632        sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
 633        sha1_finish(&hash_ctx, auth_session->nonce_odd);
 634
 635        if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
 636                             0, auth_session->handle,
 637                             auth_nonce_odd_offset, auth_session->nonce_odd,
 638                             DIGEST_LENGTH,
 639                             auth_continue_offset, 1))
 640                return TPM_LIB_ERROR;
 641        if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
 642                             DIGEST_LENGTH,
 643                             auth_session->nonce_even,
 644                             DIGEST_LENGTH,
 645                             2 * DIGEST_LENGTH,
 646                             request_auth + auth_nonce_odd_offset,
 647                             DIGEST_LENGTH + 1))
 648                return TPM_LIB_ERROR;
 649        sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
 650                  request_auth + auth_auth_offset);
 651
 652        return TPM_SUCCESS;
 653}
 654
 655/**
 656 * Verify an authentication block in a response.
 657 * Since this func updates the nonce_even in the session data it has to be
 658 * called when receiving a succesfull AUTH response.
 659 * This func can verify the first as well as the second auth block (for
 660 * double authorized commands).
 661 *
 662 * @param command_code  command code of the request
 663 * @param response      pointer to the request (w/ uninitialised auth data)
 664 * @param handles_len   length of the handles area in response
 665 * @param auth_session  pointer to the (valid) auth session to be used
 666 * @param response_auth pointer to the auth block of the response to be verified
 667 * @param auth          authentication data (HMAC key)
 668 */
 669static uint32_t verify_response_auth(uint32_t command_code,
 670        const void *response, size_t response_len0,
 671        size_t handles_len,
 672        struct session_data *auth_session,
 673        const void *response_auth, const void *auth)
 674{
 675        uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
 676        uint8_t computed_auth[DIGEST_LENGTH];
 677        sha1_context hash_ctx;
 678        const size_t return_code_offset = 6;
 679        const size_t auth_continue_offset = 20;
 680        const size_t auth_auth_offset = 21;
 681        uint8_t auth_continue;
 682
 683        if (!auth_session || !auth_session->valid)
 684                return TPM_AUTHFAIL;
 685        if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
 686                             0, command_code))
 687                return TPM_LIB_ERROR;
 688        if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
 689                return TPM_LIB_ERROR;
 690
 691        sha1_starts(&hash_ctx);
 692        sha1_update(&hash_ctx, response + return_code_offset, 4);
 693        sha1_update(&hash_ctx, hmac_data, 4);
 694        if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
 695                sha1_update(&hash_ctx,
 696                            response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
 697                            response_len0 - TPM_RESPONSE_HEADER_LENGTH
 698                            - handles_len);
 699        sha1_finish(&hash_ctx, hmac_data);
 700
 701        memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
 702        auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
 703        if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
 704                             DIGEST_LENGTH,
 705                             response_auth,
 706                             DIGEST_LENGTH,
 707                             2 * DIGEST_LENGTH,
 708                             auth_session->nonce_odd,
 709                             DIGEST_LENGTH,
 710                             3 * DIGEST_LENGTH,
 711                             auth_continue))
 712                return TPM_LIB_ERROR;
 713
 714        sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
 715                  computed_auth);
 716
 717        if (memcmp(computed_auth, response_auth + auth_auth_offset,
 718                   DIGEST_LENGTH))
 719                return TPM_AUTHFAIL;
 720
 721        return TPM_SUCCESS;
 722}
 723
 724
 725uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
 726{
 727        const uint8_t command[18] = {
 728                0x00, 0xc1,             /* TPM_TAG */
 729                0x00, 0x00, 0x00, 0x00, /* parameter size */
 730                0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
 731                0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
 732                0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
 733        };
 734        const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
 735        uint8_t request[COMMAND_BUFFER_SIZE];
 736
 737        if (pack_byte_string(request, sizeof(request), "sd",
 738                             0, command, sizeof(command),
 739                             req_handle_offset, auth_handle))
 740                return TPM_LIB_ERROR;
 741        if (oiap_session.valid && oiap_session.handle == auth_handle)
 742                oiap_session.valid = 0;
 743
 744        return tpm_sendrecv_command(request, NULL, NULL);
 745}
 746
 747uint32_t tpm_end_oiap(void)
 748{
 749        uint32_t err = TPM_SUCCESS;
 750        if (oiap_session.valid)
 751                err = tpm_terminate_auth_session(oiap_session.handle);
 752        return err;
 753}
 754
 755uint32_t tpm_oiap(uint32_t *auth_handle)
 756{
 757        const uint8_t command[10] = {
 758                0x00, 0xc1,             /* TPM_TAG */
 759                0x00, 0x00, 0x00, 0x0a, /* parameter size */
 760                0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
 761        };
 762        const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
 763        const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
 764        uint8_t response[COMMAND_BUFFER_SIZE];
 765        size_t response_length = sizeof(response);
 766        uint32_t err;
 767
 768        if (oiap_session.valid)
 769                tpm_terminate_auth_session(oiap_session.handle);
 770
 771        err = tpm_sendrecv_command(command, response, &response_length);
 772        if (err)
 773                return err;
 774        if (unpack_byte_string(response, response_length, "ds",
 775                               res_auth_handle_offset, &oiap_session.handle,
 776                               res_nonce_even_offset, &oiap_session.nonce_even,
 777                               (uint32_t)DIGEST_LENGTH))
 778                return TPM_LIB_ERROR;
 779        oiap_session.valid = 1;
 780        if (auth_handle)
 781                *auth_handle = oiap_session.handle;
 782        return 0;
 783}
 784
 785uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
 786                const void *key, size_t key_length,
 787                const void *parent_key_usage_auth,
 788                uint32_t *key_handle)
 789{
 790        const uint8_t command[14] = {
 791                0x00, 0xc2,             /* TPM_TAG */
 792                0x00, 0x00, 0x00, 0x00, /* parameter size */
 793                0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
 794                0x00, 0x00, 0x00, 0x00, /* parent handle */
 795        };
 796        const size_t req_size_offset = 2;
 797        const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
 798        const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
 799        const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
 800        uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
 801                        + TPM_REQUEST_AUTH_LENGTH];
 802        uint8_t response[COMMAND_BUFFER_SIZE];
 803        size_t response_length = sizeof(response);
 804        uint32_t err;
 805
 806        if (!oiap_session.valid) {
 807                err = tpm_oiap(NULL);
 808                if (err)
 809                        return err;
 810        }
 811        if (pack_byte_string(request, sizeof(request), "sdds",
 812                             0, command, sizeof(command),
 813                             req_size_offset,
 814                             sizeof(command) + key_length
 815                             + TPM_REQUEST_AUTH_LENGTH,
 816                             req_parent_handle_offset, parent_handle,
 817                             req_key_offset, key, key_length
 818                ))
 819                return TPM_LIB_ERROR;
 820
 821        err = create_request_auth(request, sizeof(command) + key_length, 4,
 822                                &oiap_session,
 823                                request + sizeof(command) + key_length,
 824                                parent_key_usage_auth);
 825        if (err)
 826                return err;
 827        err = tpm_sendrecv_command(request, response, &response_length);
 828        if (err) {
 829                if (err == TPM_AUTHFAIL)
 830                        oiap_session.valid = 0;
 831                return err;
 832        }
 833
 834        err = verify_response_auth(0x00000041, response,
 835                        response_length - TPM_RESPONSE_AUTH_LENGTH,
 836                        4, &oiap_session,
 837                        response + response_length - TPM_RESPONSE_AUTH_LENGTH,
 838                        parent_key_usage_auth);
 839        if (err)
 840                return err;
 841
 842        if (key_handle) {
 843                if (unpack_byte_string(response, response_length, "d",
 844                                       res_handle_offset, key_handle))
 845                        return TPM_LIB_ERROR;
 846        }
 847
 848        return 0;
 849}
 850
 851uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
 852                        void *pubkey, size_t *pubkey_len)
 853{
 854        const uint8_t command[14] = {
 855                0x00, 0xc2,             /* TPM_TAG */
 856                0x00, 0x00, 0x00, 0x00, /* parameter size */
 857                0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
 858                0x00, 0x00, 0x00, 0x00, /* key handle */
 859        };
 860        const size_t req_size_offset = 2;
 861        const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
 862        const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
 863        uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
 864        uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
 865                        + TPM_RESPONSE_AUTH_LENGTH];
 866        size_t response_length = sizeof(response);
 867        uint32_t err;
 868
 869        if (!oiap_session.valid) {
 870                err = tpm_oiap(NULL);
 871                if (err)
 872                        return err;
 873        }
 874        if (pack_byte_string(request, sizeof(request), "sdd",
 875                             0, command, sizeof(command),
 876                             req_size_offset,
 877                             (uint32_t)(sizeof(command)
 878                             + TPM_REQUEST_AUTH_LENGTH),
 879                             req_key_handle_offset, key_handle
 880                ))
 881                return TPM_LIB_ERROR;
 882        err = create_request_auth(request, sizeof(command), 4, &oiap_session,
 883                        request + sizeof(command), usage_auth);
 884        if (err)
 885                return err;
 886        err = tpm_sendrecv_command(request, response, &response_length);
 887        if (err) {
 888                if (err == TPM_AUTHFAIL)
 889                        oiap_session.valid = 0;
 890                return err;
 891        }
 892        err = verify_response_auth(0x00000021, response,
 893                        response_length - TPM_RESPONSE_AUTH_LENGTH,
 894                        0, &oiap_session,
 895                        response + response_length - TPM_RESPONSE_AUTH_LENGTH,
 896                        usage_auth);
 897        if (err)
 898                return err;
 899
 900        if (pubkey) {
 901                if ((response_length - TPM_RESPONSE_HEADER_LENGTH
 902                        - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
 903                        return TPM_LIB_ERROR;
 904                *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
 905                        - TPM_RESPONSE_AUTH_LENGTH;
 906                memcpy(pubkey, response + res_pubkey_offset,
 907                       response_length - TPM_RESPONSE_HEADER_LENGTH
 908                       - TPM_RESPONSE_AUTH_LENGTH);
 909        }
 910
 911        return 0;
 912}
 913
 914#endif /* CONFIG_TPM_AUTH_SESSIONS */
 915