uboot/lib/tpm-v2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2018 Bootlin
   4 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <tpm-common.h>
  10#include <tpm-v2.h>
  11#include "tpm-utils.h"
  12
  13u32 tpm2_startup(enum tpm2_startup_types mode)
  14{
  15        const u8 command_v2[12] = {
  16                tpm_u16(TPM2_ST_NO_SESSIONS),
  17                tpm_u32(12),
  18                tpm_u32(TPM2_CC_STARTUP),
  19                tpm_u16(mode),
  20        };
  21        int ret;
  22
  23        /*
  24         * Note TPM2_Startup command will return RC_SUCCESS the first time,
  25         * but will return RC_INITIALIZE otherwise.
  26         */
  27        ret = tpm_sendrecv_command(command_v2, NULL, NULL);
  28        if (ret && ret != TPM2_RC_INITIALIZE)
  29                return ret;
  30
  31        return 0;
  32}
  33
  34u32 tpm2_self_test(enum tpm2_yes_no full_test)
  35{
  36        const u8 command_v2[12] = {
  37                tpm_u16(TPM2_ST_NO_SESSIONS),
  38                tpm_u32(11),
  39                tpm_u32(TPM2_CC_SELF_TEST),
  40                full_test,
  41        };
  42
  43        return tpm_sendrecv_command(command_v2, NULL, NULL);
  44}
  45
  46u32 tpm2_clear(u32 handle, const char *pw, const ssize_t pw_sz)
  47{
  48        u8 command_v2[COMMAND_BUFFER_SIZE] = {
  49                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
  50                tpm_u32(27 + pw_sz),            /* Length */
  51                tpm_u32(TPM2_CC_CLEAR),         /* Command code */
  52
  53                /* HANDLE */
  54                tpm_u32(handle),                /* TPM resource handle */
  55
  56                /* AUTH_SESSION */
  57                tpm_u32(9 + pw_sz),             /* Authorization size */
  58                tpm_u32(TPM2_RS_PW),            /* Session handle */
  59                tpm_u16(0),                     /* Size of <nonce> */
  60                                                /* <nonce> (if any) */
  61                0,                              /* Attributes: Cont/Excl/Rst */
  62                tpm_u16(pw_sz),                 /* Size of <hmac/password> */
  63                /* STRING(pw)                      <hmac/password> (if any) */
  64        };
  65        unsigned int offset = 27;
  66        int ret;
  67
  68        /*
  69         * Fill the command structure starting from the first buffer:
  70         *     - the password (if any)
  71         */
  72        ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
  73                               offset, pw, pw_sz);
  74        offset += pw_sz;
  75        if (ret)
  76                return TPM_LIB_ERROR;
  77
  78        return tpm_sendrecv_command(command_v2, NULL, NULL);
  79}
  80
  81u32 tpm2_pcr_extend(u32 index, const uint8_t *digest)
  82{
  83        u8 command_v2[COMMAND_BUFFER_SIZE] = {
  84                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
  85                tpm_u32(33 + TPM2_DIGEST_LEN),  /* Length */
  86                tpm_u32(TPM2_CC_PCR_EXTEND),    /* Command code */
  87
  88                /* HANDLE */
  89                tpm_u32(index),                 /* Handle (PCR Index) */
  90
  91                /* AUTH_SESSION */
  92                tpm_u32(9),                     /* Authorization size */
  93                tpm_u32(TPM2_RS_PW),            /* Session handle */
  94                tpm_u16(0),                     /* Size of <nonce> */
  95                                                /* <nonce> (if any) */
  96                0,                              /* Attributes: Cont/Excl/Rst */
  97                tpm_u16(0),                     /* Size of <hmac/password> */
  98                                                /* <hmac/password> (if any) */
  99                tpm_u32(1),                     /* Count (number of hashes) */
 100                tpm_u16(TPM2_ALG_SHA256),       /* Algorithm of the hash */
 101                /* STRING(digest)                  Digest */
 102        };
 103        unsigned int offset = 33;
 104        int ret;
 105
 106        /*
 107         * Fill the command structure starting from the first buffer:
 108         *     - the digest
 109         */
 110        ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
 111                               offset, digest, TPM2_DIGEST_LEN);
 112        offset += TPM2_DIGEST_LEN;
 113        if (ret)
 114                return TPM_LIB_ERROR;
 115
 116        return tpm_sendrecv_command(command_v2, NULL, NULL);
 117}
 118
 119u32 tpm2_pcr_read(u32 idx, unsigned int idx_min_sz, void *data,
 120                  unsigned int *updates)
 121{
 122        u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
 123        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 124                tpm_u16(TPM2_ST_NO_SESSIONS),   /* TAG */
 125                tpm_u32(17 + idx_array_sz),     /* Length */
 126                tpm_u32(TPM2_CC_PCR_READ),      /* Command code */
 127
 128                /* TPML_PCR_SELECTION */
 129                tpm_u32(1),                     /* Number of selections */
 130                tpm_u16(TPM2_ALG_SHA256),       /* Algorithm of the hash */
 131                idx_array_sz,                   /* Array size for selection */
 132                /* bitmap(idx)                     Selected PCR bitmap */
 133        };
 134        size_t response_len = COMMAND_BUFFER_SIZE;
 135        u8 response[COMMAND_BUFFER_SIZE];
 136        unsigned int pcr_sel_idx = idx / 8;
 137        u8 pcr_sel_bit = BIT(idx % 8);
 138        unsigned int counter = 0;
 139        int ret;
 140
 141        if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
 142                             17 + pcr_sel_idx, pcr_sel_bit))
 143                return TPM_LIB_ERROR;
 144
 145        ret = tpm_sendrecv_command(command_v2, response, &response_len);
 146        if (ret)
 147                return ret;
 148
 149        if (unpack_byte_string(response, response_len, "ds",
 150                               10, &counter,
 151                               response_len - TPM2_DIGEST_LEN, data,
 152                               TPM2_DIGEST_LEN))
 153                return TPM_LIB_ERROR;
 154
 155        if (updates)
 156                *updates = counter;
 157
 158        return 0;
 159}
 160
 161u32 tpm2_get_capability(u32 capability, u32 property, void *buf,
 162                        size_t prop_count)
 163{
 164        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 165                tpm_u16(TPM2_ST_NO_SESSIONS),           /* TAG */
 166                tpm_u32(22),                            /* Length */
 167                tpm_u32(TPM2_CC_GET_CAPABILITY),        /* Command code */
 168
 169                tpm_u32(capability),                    /* Capability */
 170                tpm_u32(property),                      /* Property */
 171                tpm_u32(prop_count),                    /* Property count */
 172        };
 173        u8 response[COMMAND_BUFFER_SIZE];
 174        size_t response_len = COMMAND_BUFFER_SIZE;
 175        unsigned int properties_off;
 176        int ret;
 177
 178        ret = tpm_sendrecv_command(command_v2, response, &response_len);
 179        if (ret)
 180                return ret;
 181
 182        /*
 183         * In the response buffer, the properties are located after the:
 184         * tag (u16), response size (u32), response code (u32),
 185         * YES/NO flag (u8), TPM_CAP (u32) and TPMU_CAPABILITIES (u32).
 186         */
 187        properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
 188                         sizeof(u8) + sizeof(u32) + sizeof(u32);
 189        memcpy(buf, &response[properties_off], response_len - properties_off);
 190
 191        return 0;
 192}
 193
 194u32 tpm2_dam_reset(const char *pw, const ssize_t pw_sz)
 195{
 196        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 197                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
 198                tpm_u32(27 + pw_sz),            /* Length */
 199                tpm_u32(TPM2_CC_DAM_RESET),     /* Command code */
 200
 201                /* HANDLE */
 202                tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
 203
 204                /* AUTH_SESSION */
 205                tpm_u32(9 + pw_sz),             /* Authorization size */
 206                tpm_u32(TPM2_RS_PW),            /* Session handle */
 207                tpm_u16(0),                     /* Size of <nonce> */
 208                                                /* <nonce> (if any) */
 209                0,                              /* Attributes: Cont/Excl/Rst */
 210                tpm_u16(pw_sz),                 /* Size of <hmac/password> */
 211                /* STRING(pw)                      <hmac/password> (if any) */
 212        };
 213        unsigned int offset = 27;
 214        int ret;
 215
 216        /*
 217         * Fill the command structure starting from the first buffer:
 218         *     - the password (if any)
 219         */
 220        ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
 221                               offset, pw, pw_sz);
 222        offset += pw_sz;
 223        if (ret)
 224                return TPM_LIB_ERROR;
 225
 226        return tpm_sendrecv_command(command_v2, NULL, NULL);
 227}
 228
 229u32 tpm2_dam_parameters(const char *pw, const ssize_t pw_sz,
 230                        unsigned int max_tries, unsigned int recovery_time,
 231                        unsigned int lockout_recovery)
 232{
 233        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 234                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
 235                tpm_u32(27 + pw_sz + 12),       /* Length */
 236                tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
 237
 238                /* HANDLE */
 239                tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
 240
 241                /* AUTH_SESSION */
 242                tpm_u32(9 + pw_sz),             /* Authorization size */
 243                tpm_u32(TPM2_RS_PW),            /* Session handle */
 244                tpm_u16(0),                     /* Size of <nonce> */
 245                                                /* <nonce> (if any) */
 246                0,                              /* Attributes: Cont/Excl/Rst */
 247                tpm_u16(pw_sz),                 /* Size of <hmac/password> */
 248                /* STRING(pw)                      <hmac/password> (if any) */
 249
 250                /* LOCKOUT PARAMETERS */
 251                /* tpm_u32(max_tries)              Max tries (0, always lock) */
 252                /* tpm_u32(recovery_time)          Recovery time (0, no lock) */
 253                /* tpm_u32(lockout_recovery)       Lockout recovery */
 254        };
 255        unsigned int offset = 27;
 256        int ret;
 257
 258        /*
 259         * Fill the command structure starting from the first buffer:
 260         *     - the password (if any)
 261         *     - max tries
 262         *     - recovery time
 263         *     - lockout recovery
 264         */
 265        ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
 266                               offset, pw, pw_sz,
 267                               offset + pw_sz, max_tries,
 268                               offset + pw_sz + 4, recovery_time,
 269                               offset + pw_sz + 8, lockout_recovery);
 270        offset += pw_sz + 12;
 271        if (ret)
 272                return TPM_LIB_ERROR;
 273
 274        return tpm_sendrecv_command(command_v2, NULL, NULL);
 275}
 276
 277int tpm2_change_auth(u32 handle, const char *newpw, const ssize_t newpw_sz,
 278                     const char *oldpw, const ssize_t oldpw_sz)
 279{
 280        unsigned int offset = 27;
 281        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 282                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
 283                tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
 284                tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
 285
 286                /* HANDLE */
 287                tpm_u32(handle),                /* TPM resource handle */
 288
 289                /* AUTH_SESSION */
 290                tpm_u32(9 + oldpw_sz),          /* Authorization size */
 291                tpm_u32(TPM2_RS_PW),            /* Session handle */
 292                tpm_u16(0),                     /* Size of <nonce> */
 293                                                /* <nonce> (if any) */
 294                0,                              /* Attributes: Cont/Excl/Rst */
 295                tpm_u16(oldpw_sz)               /* Size of <hmac/password> */
 296                /* STRING(oldpw)                   <hmac/password> (if any) */
 297
 298                /* TPM2B_AUTH (TPM2B_DIGEST) */
 299                /* tpm_u16(newpw_sz)               Digest size, new pw length */
 300                /* STRING(newpw)                   Digest buffer, new pw */
 301        };
 302        int ret;
 303
 304        /*
 305         * Fill the command structure starting from the first buffer:
 306         *     - the old password (if any)
 307         *     - size of the new password
 308         *     - new password
 309         */
 310        ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
 311                               offset, oldpw, oldpw_sz,
 312                               offset + oldpw_sz, newpw_sz,
 313                               offset + oldpw_sz + 2, newpw, newpw_sz);
 314        offset += oldpw_sz + 2 + newpw_sz;
 315        if (ret)
 316                return TPM_LIB_ERROR;
 317
 318        return tpm_sendrecv_command(command_v2, NULL, NULL);
 319}
 320
 321u32 tpm2_pcr_setauthpolicy(const char *pw, const ssize_t pw_sz, u32 index,
 322                           const char *key)
 323{
 324        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 325                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
 326                tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
 327                tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
 328
 329                /* HANDLE */
 330                tpm_u32(TPM2_RH_PLATFORM),      /* TPM resource handle */
 331
 332                /* AUTH_SESSION */
 333                tpm_u32(9 + pw_sz),             /* Authorization size */
 334                tpm_u32(TPM2_RS_PW),            /* session handle */
 335                tpm_u16(0),                     /* Size of <nonce> */
 336                                                /* <nonce> (if any) */
 337                0,                              /* Attributes: Cont/Excl/Rst */
 338                tpm_u16(pw_sz)                  /* Size of <hmac/password> */
 339                /* STRING(pw)                      <hmac/password> (if any) */
 340
 341                /* TPM2B_AUTH (TPM2B_DIGEST) */
 342                /* tpm_u16(TPM2_DIGEST_LEN)        Digest size length */
 343                /* STRING(key)                     Digest buffer (PCR key) */
 344
 345                /* TPMI_ALG_HASH */
 346                /* tpm_u16(TPM2_ALG_SHA256)   Algorithm of the hash */
 347
 348                /* TPMI_DH_PCR */
 349                /* tpm_u32(index),                 PCR Index */
 350        };
 351        unsigned int offset = 27;
 352        int ret;
 353
 354        /*
 355         * Fill the command structure starting from the first buffer:
 356         *     - the password (if any)
 357         *     - the PCR key length
 358         *     - the PCR key
 359         *     - the hash algorithm
 360         *     - the PCR index
 361         */
 362        ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
 363                               offset, pw, pw_sz,
 364                               offset + pw_sz, TPM2_DIGEST_LEN,
 365                               offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
 366                               offset + pw_sz + 2 + TPM2_DIGEST_LEN,
 367                               TPM2_ALG_SHA256,
 368                               offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
 369        offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
 370        if (ret)
 371                return TPM_LIB_ERROR;
 372
 373        return tpm_sendrecv_command(command_v2, NULL, NULL);
 374}
 375
 376u32 tpm2_pcr_setauthvalue(const char *pw, const ssize_t pw_sz, u32 index,
 377                          const char *key, const ssize_t key_sz)
 378{
 379        u8 command_v2[COMMAND_BUFFER_SIZE] = {
 380                tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
 381                tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
 382                tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
 383
 384                /* HANDLE */
 385                tpm_u32(index),                 /* Handle (PCR Index) */
 386
 387                /* AUTH_SESSION */
 388                tpm_u32(9 + pw_sz),             /* Authorization size */
 389                tpm_u32(TPM2_RS_PW),            /* session handle */
 390                tpm_u16(0),                     /* Size of <nonce> */
 391                                                /* <nonce> (if any) */
 392                0,                              /* Attributes: Cont/Excl/Rst */
 393                tpm_u16(pw_sz),                 /* Size of <hmac/password> */
 394                /* STRING(pw)                      <hmac/password> (if any) */
 395
 396                /* TPM2B_DIGEST */
 397                /* tpm_u16(key_sz)                 Key length */
 398                /* STRING(key)                     Key */
 399        };
 400        unsigned int offset = 27;
 401        int ret;
 402
 403        /*
 404         * Fill the command structure starting from the first buffer:
 405         *     - the password (if any)
 406         *     - the number of digests, 1 in our case
 407         *     - the algorithm, sha256 in our case
 408         *     - the digest (64 bytes)
 409         */
 410        ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
 411                               offset, pw, pw_sz,
 412                               offset + pw_sz, key_sz,
 413                               offset + pw_sz + 2, key, key_sz);
 414        offset += pw_sz + 2 + key_sz;
 415        if (ret)
 416                return TPM_LIB_ERROR;
 417
 418        return tpm_sendrecv_command(command_v2, NULL, NULL);
 419}
 420