Re: [PATCH v3 0/6] Updated API for TPM 2.0 PCR extend

Roberto Sassu
2017-06-26T06:58:43Z

On 6/24/2017 11:03 AM, Jarkko Sakkinen wrote:
> On Wed, Jun 21, 2017 at 04:29:35PM +0200, Roberto Sassu wrote:
>> The first version of the patch set can be retrieved at the URL:
>>
>> https://sourceforge.net/p/tpmdd/mailman/message/35756302/
>>
>> The patches should be applied on top of the next branch of
>> linux-security.git (commit cdac74d).
>>
>> This patch set updates the TPM driver API for extending Platform
>> Configuration Registers (PCRs). These are special TPM registers which
>> cannot be written directly, but can only be updated through the extend
>> operation, by passing a digest as input:
>>
>> PCR_value_new = hash_func(PCR_value_old | digest)
>>
>> While TPM 1.2 can only use SHA1 as hash function, TPM 2.0 can support
>> multiple algorithms. On a TPM 2.0, PCR values extended with the same
>> algorithm are stored in a location called bank.
>>
>> Currently, PCRs can only be extended from the kernel with a SHA1 digest,
>> through tpm_pcr_extend(). Remaining banks of a TPM 2.0 are extended with
>> the SHA1 digest padded with zeros. In order to take advantage of stronger
>> algorithms, the TPM driver should allow TPM users to extend a PCR with
>> digests calculated with the same algorithm of the PCR bank.
>>
>> This patch set first introduces a new structure, called tpm_pcr_bank_info,
>> for storing detailed information about each PCR bank:
>>
>> - TPM algorithm ID: algorithm identifier, defined by TCG; will be included
>> by TPM users (e.g. IMA) in a measurement event log
>> - digest size: digest size for a TPM algorithm; since this is retrieved
>> from the TPM, PCR banks can be extended even if an algorithm is unknown
>> for the crypto subsystem (which currently the TPM driver relies on)
>> - crypto ID: will be used by TPM users to calculate a digest, to extend
>> a PCR
>>
>> Then, the patch set introduces the new function tpm_get_pcr_banks_info(),
>> to pass the information about PCR banks to TPM users, and finally, modifies
>> the parameters of tpm_pcr_extend(), so that TPM users can pass multiple
>> digests.
>>
>> Given this definition of the tpm2_digest structure:
>>
>> struct tpm2_digest {
>> u16 alg_id;
>> u8 digest[SHA512_DIGEST_SIZE];
>> } __packed;
>>
>> there will be two methods to extend PCRs:
>>
>> 1) by passing only one tpm2_digest structure containing a SHA1 digest
>> (as it is done in the patch 6/6); in this case, the SHA1 digest
>> is padded with zeros
>>
>> 2) by calling tpm_get_pcr_banks_info() to obtain PCR banks information,
>> and by calling tpm_pcr_extend() with as many tpm2_digest structures as
>> the number of tpm_pcr_bank_info structures retrieved in the first step
>> (if a digest for a TPM algorithm is missing, the TPM driver
>> pads/truncates the first digest provided by the TPM user)
>>
>>
>> API Usage Examples
>>
>> In the following examples, an application extends PCR 16 with the digest
>> of an event (e.g. record of a software measurement), with the methods
>> described above.
>>
>>
>> void app_calc_event_digest(struct crypto_shash *tfm, char *event,
>> u8 *digest)
>> {
>> SHASH_DESC_ON_STACK(shash, tfm);
>>
>> shash->tfm = tfm;
>> shash->flags = 0;
>>
>> crypto_shash_init(shash);
>> crypto_shash_update(shash, event, strlen(event));
>> crypto_shash_final(shash, digest);
>> }
>>
>> void app_pcr_extend_method_1(void)
>> {
>> char *event = "application event";
>> struct tpm2_digest digestarg = {.alg_id = TPM2_ALG_SHA1};
>>
>> /* calculate event digest with current hash algorithm */
>> struct crypto_shash *tfm = crypto_alloc_shash("sha1", 0, 0);
>>
>> app_calc_event_digest(tfm, event, digestarg.digest);
>>
>> /* extend all PCR banks with SHA1 digest*/
>> tpm_pcr_extend(TPM_ANY_NUM, 16, 1, &digestarg);
>> }
>>
>> void app_pcr_extend_method_2(void)
>> {
>> /* declare static arrays, limit is known */
>> struct tpm_pcr_bank_info active_banks[TPM_ACTIVE_BANKS_MAX];
>> struct tpm2_digest digest_array[TPM_ACTIVE_BANKS_MAX];
>> int i, num_algo;
>>
>> /* obtain algorithms supported by the TPM */
>> num_algo = tpm_get_pcr_banks_info(TPM_ANY_NUM, active_banks);
>>
>> for (i = 0; i < num_algo; i++) {
>> char *event = "application event";
>>
>> /* calculate event digest with current hash algorithm */
>> const char *algo_name = hash_algo_name[active_banks[i].crypto_id];
>> struct crypto_shash *tfm = crypto_alloc_shash(algo_name, 0, 0);
>>
>> app_calc_event_digest(tfm, event, digest_array[i].digest);
>> digest_array[i].alg_id = active_banks[i].alg_id;
>> }
>>
>> /* extend all PCR banks with calculated digests */
>> tpm_pcr_extend(TPM_ANY_NUM, 16, num_algo, digest_array);
>> }
>>
>>
>> Changelog
>>
>> v3
>>
>> - introduced new structure tpm_pcr_bank_info
>> - read a PCR to obtain the digest size for each TPM algorithm
>> - tpm_pcr_algorithms() replaced by tpm_get_pcr_banks_info()
>> - removed tpm_pcr_algo_to_crypto() and tpm_pcr_algo_from_crypto()
>> - modification of tpm_pcr_extend() parameters and of callers of the
>> function done in the same patch
>> - removed tpm_pcr_check_input()
>>
>> v2
>>
>> - tpm_pcr_algorithms() returns supported algorithms also for TPM 1.2
>> - fixed return values of tpm2_pcr_algo_to_crypto() and
>> tpm2_pcr_algo_from_crypto() if TPM support is disabled in the kernel
>> - tpm_pcr_extend() arguments checked by tpm_pcr_check_input()
>> - modified parameters of tpm_pcr_extend()
>>
>> Roberto Sassu (6):
>> tpm: use tpm_buf functions to perform a PCR read
>> tpm: use tpm2_pcr_read_tpm_buf() in tpm2_do_selftest()
>> tpm: introduce tpm_pcr_bank_info structure with digest_size from TPM
>> tpm: replace TPM algorithms IDs with tpm_pcr_bank_info structs in
>> tpm_chip
>> tpm: introduce tpm_get_pcr_banks_info()
>> tpm: pass multiple digests to tpm_pcr_extend()
>>
>> drivers/char/tpm/tpm-interface.c | 88 ++++++++++++++++++++++---
>> drivers/char/tpm/tpm.h | 19 +-----
>> drivers/char/tpm/tpm2-cmd.c | 132 ++++++++++++++++++++++---------------
>> include/linux/tpm.h | 39 ++++++++++-
>> security/integrity/ima/ima_queue.c | 4 +-
>> security/keys/trusted.c | 6 +-
>> 6 files changed, 202 insertions(+), 86 deletions(-)
>>
>> --
>> 2.9.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe keyrings" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> To move this forward and be more constructive here's how I see it
> should be done (along the lines, draft):
>
> int tpm_pcr_extend(u32 chip_num, int pcr_idx, unsigned int alg,
> const u8 *hash);
>
> The paramater 'alg' is crypto ID as specified by crypto subsystem.
>
> TPM driver must have a precompiled table of mappings for crypto IDs
> and TPM algorithm IDs.
>
> In addition it must have dynamically acquired list of TPM alg IDs.
> For those algs that static mapping does not exist it must extend
> them like we do now everything else except SHA-1 (Naynas changes).

Algorithms for which there is no mapping are skipped.

How you can build the command buffer if you don't know the digest size?

Roberto

> There's absolutely no need to pass digest size like you do BTW as it is
> defined by the standard.
>
> I also except that where ever this interleaves with trusted keys there
> won't be duplicate structures and code.
>
> /Jarkko
>

--
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Qiuen PENG, Shengli WANG