Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp52093pxb; Fri, 19 Feb 2021 17:40:27 -0800 (PST) X-Google-Smtp-Source: ABdhPJz17ntHrvbY1+2f0ucIbhI0A6YCDhEjKhqpEX21iKvzrd/mvg36e/jB9KD+FJzXue666y02 X-Received: by 2002:a17:906:4102:: with SMTP id j2mr2249846ejk.460.1613785227371; Fri, 19 Feb 2021 17:40:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613785227; cv=none; d=google.com; s=arc-20160816; b=iJ8X+OoSwT7NhAhkphA9qiUmvLiztpLtiV3BnVJRkTrbxuZ7q0eUnJ7kIJgrAmQ4Si p0dgMkl+2p307OM3AST5tXSdHnAWYvp+3JX5ZAn1fl0/qfCFNLIqfQQi3DokYFuajg0j y2+AOJsYV1yCFeM98zpbgxONDECsZjd3+LAcsuBWJlP+vaibMr4mvpVt7IskE6kNE2EE dTZgqS9ViVw/sscOvb6un5HOVrZ0DXK8HGfKkF+WB+JojZi9XLiq2LPcQfn9C3Cqg2m8 YUrOc8z6SryOefbF6uy1VMekKLn2+E5CxZi1YNXA3Hx4j1g3ePwC1sNn75+Zi6p4Cgvj hLvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:sender:dkim-signature; bh=Le2xy86M2g7vFjnuX/RXj2Z9OeFij6CrkPXndbL+3YM=; b=iLWjNdyK0PIgd5aaPOSybkvP6RGF9eOQ+0vttckHAzy9fwZubLvgC/7ZIfJhSRjxq0 oLjC9OcK07gpnUFvKkXhkMfGN9HNlgfehup2zKkHY5cgO6rmrnMde147iDJZzufv2/wu V9HOE0NaHoW04naAY2EZeSrT7qGV3KdVe81FxzPCRxebyrHnjxSjHXGq8Hv72RA9LDp8 KQAA8VKwLw9bz/jr+U8wOj2iLh02jMCyO3yvfpjtA4SG1f9jK6szXnczZ6dZ6h4+oKuf UUczrPyZW0PwfskLP6KtW9ujvGrOweTm1/ysteJ3+wMFzL1MGyfJ5vqrXvJ7fqbYE98B iaGg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=mUmzPMLQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c10si6967145edk.143.2021.02.19.17.40.05; Fri, 19 Feb 2021 17:40:27 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=mUmzPMLQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230074AbhBTBgO (ORCPT + 99 others); Fri, 19 Feb 2021 20:36:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44170 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229947AbhBTBfC (ORCPT ); Fri, 19 Feb 2021 20:35:02 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F0BAC061A2D for ; Fri, 19 Feb 2021 17:33:20 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id o9so8711616yba.18 for ; Fri, 19 Feb 2021 17:33:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=Le2xy86M2g7vFjnuX/RXj2Z9OeFij6CrkPXndbL+3YM=; b=mUmzPMLQ2EhM5ohqQmvRX3zzjTI4HWgSEU8OF6ChUOqqCnyRmUWuS7Fg85iVRVC6D0 tlS1Qf9auwUtImh2HiRyyIF9zKTBlptAOolf0FoHdiiUmi0OW/MbiiVc5aFxLp0Ixvg1 cFeCJz9zZMvDoZq8E4OJNEyCKW06WEsbbi1WGGYwxmWGValJTlOySL2JTQ+lyT9DZEcG H2uY8kjDRo7fTGbtIHU0o77/si0NRfV4D/hT8to4ifU0A4zu8NUO1F1mRowKzzBwornS TsK6HQUR5c3H2o4BOGqBx1XATTaJyYRtgg6nD/nS2R0cTSOvXH5a/+N4HO8Uwo08O0Ik vzfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Le2xy86M2g7vFjnuX/RXj2Z9OeFij6CrkPXndbL+3YM=; b=fApYim7+9moADA3yOu/ohuH1nDLe4IdZLtjDf9pele3RkK6n0Rsf2xC/WP6YLNKsoY oXK0/eo7BsKrHOpw0p3hXUNb2q9UXXJGclGknGfCbp8hIMRE+Nc+ASjcmoaX8Vm8JeCA 7mppknl9Qms5Rg9os8mUIkXdNsV33SKlddTW13ubYP9boGeIEoM/QkA7JbWHX1EAU00O 8v3YpnRwI40j9rEsg4eyXRYsXkLAiEkjltk6hjVHf6cU3KV0W1GiF1lHId07XogK5M4z CdaFG/ElY040xVGmAM7lTUfdWJWYPBQFoKGr0TkH1qwVOJcFOH3stgnwSv/o97QjdtfD 6Leg== X-Gm-Message-State: AOAM532Yl98N2XGIUAsMKm49JXnnatlHVnbMkWP3vC/pUaDpZdjOsMe3 7+Ex9WA4OzhEvCMK7L62qhYKbwTL3rKqKBFCr5oop8v2/hRWXFSL6VI7ZV2X+6ENwK3BD5kyuek X5tX6q/Dm1ZH4sBZG6TUbKMwGRoMpkWAXP9M0wH8nkw2ihCxpZ9LVmNCoXoYWk0290m1fZ9l0qR bZvVOpZhymkGkzYfU= Sender: "matthewgarrett via sendgmr" X-Received: from matthewgarrett-tmp.c.googlers.com ([fda3:e722:ac3:10:7f:e700:c0a8:1081]) (user=matthewgarrett job=sendgmr) by 2002:a25:a0c9:: with SMTP id i9mr15696415ybm.479.1613784799467; Fri, 19 Feb 2021 17:33:19 -0800 (PST) Date: Sat, 20 Feb 2021 01:32:54 +0000 In-Reply-To: <20210220013255.1083202-1-matthewgarrett@google.com> Message-Id: <20210220013255.1083202-9-matthewgarrett@google.com> Mime-Version: 1.0 References: <20210220013255.1083202-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.30.0.617.g56c4b15f3c-goog Subject: [PATCH 8/9] pm: hibernate: Verify the digest encryption key From: Matthew Garrett To: linux-kernel@vger.kernel.org Cc: linux-integrity@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, zohar@linux.ibm.com, jejb@linux.ibm.com, jarkko@kernel.org, corbet@lwn.net, rjw@rjwysocki.net, Matthew Garrett , Matthew Garrett Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org We want to ensure that the key used to encrypt the digest was created by the kernel during hibernation. To do this we request that the TPM include information about the value of PCR 23 at the time of key creation in the sealed blob. On resume, we can ask the TPM to certify that the creation data is accurate and then make sure that the PCR information in the blob corresponds to the expected value. Since only the kernel can touch PCR 23, if an attacker generates a key themselves the value of PCR 23 will have been different, allowing us to reject the key and boot normally instead of resuming. Signed-off-by: Matthew Garrett --- include/linux/tpm.h | 1 + kernel/power/tpm.c | 150 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 3 deletions(-) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index e2075e2242a0..f6970986b097 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -216,6 +216,7 @@ enum tpm2_command_codes { TPM2_CC_SELF_TEST = 0x0143, TPM2_CC_STARTUP = 0x0144, TPM2_CC_SHUTDOWN = 0x0145, + TPM2_CC_CERTIFYCREATION = 0x014A, TPM2_CC_NV_READ = 0x014E, TPM2_CC_CREATE = 0x0153, TPM2_CC_LOAD = 0x0157, diff --git a/kernel/power/tpm.c b/kernel/power/tpm.c index 953dcbdc56d8..34e6cfb98ce4 100644 --- a/kernel/power/tpm.c +++ b/kernel/power/tpm.c @@ -14,6 +14,12 @@ static struct tpm_digest digest = { .alg_id = TPM_ALG_SHA256, 0xf1, 0x22, 0x38, 0x6c, 0x33, 0xb1, 0x14, 0xb7, 0xec, 0x05, 0x5f, 0x49}}; +/* sha256(sha256(empty_pcr | digest)) */ +static char expected_digest[] = {0x2f, 0x96, 0xf2, 0x1b, 0x70, 0xa9, 0xe8, + 0x42, 0x25, 0x8e, 0x66, 0x07, 0xbe, 0xbc, 0xe3, 0x1f, 0x2c, 0x84, 0x4a, + 0x3f, 0x85, 0x17, 0x31, 0x47, 0x9a, 0xa5, 0x53, 0xbb, 0x23, 0x0c, 0x32, + 0xf3}; + struct skcipher_def { struct scatterlist sg; struct crypto_skcipher *tfm; @@ -21,6 +27,39 @@ struct skcipher_def { struct crypto_wait wait; }; +static int sha256_data(char *buf, int size, char *output) +{ + struct crypto_shash *tfm; + struct shash_desc *desc; + int ret; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + desc = kmalloc(sizeof(struct shash_desc) + + crypto_shash_descsize(tfm), GFP_KERNEL); + if (!desc) { + crypto_free_shash(tfm); + return -ENOMEM; + } + + desc->tfm = tfm; + ret = crypto_shash_init(desc); + if (ret != 0) { + crypto_free_shash(tfm); + kfree(desc); + return ret; + } + + crypto_shash_update(desc, buf, size); + crypto_shash_final(desc, output); + crypto_free_shash(desc->tfm); + kfree(desc); + + return 0; +} + static int swsusp_enc_dec(struct trusted_key_payload *payload, char *buf, int enc) { @@ -86,6 +125,58 @@ static int swsusp_enc_dec(struct trusted_key_payload *payload, char *buf, return ret; } +static int tpm_certify_creationdata(struct tpm_chip *chip, + struct trusted_key_payload *payload) +{ + struct tpm_header *head; + struct tpm_buf buf; + int rc; + + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CERTIFYCREATION); + if (rc) + return rc; + + /* Use TPM_RH_NULL for signHandle */ + tpm_buf_append_u32(&buf, 0x40000007); + + /* Object handle */ + tpm_buf_append_u32(&buf, payload->blob_handle); + + /* Auth */ + tpm_buf_append_u32(&buf, 9); + tpm_buf_append_u32(&buf, TPM2_RS_PW); + tpm_buf_append_u16(&buf, 0); + tpm_buf_append_u8(&buf, 0); + tpm_buf_append_u16(&buf, 0); + + /* Qualifying data */ + tpm_buf_append_u16(&buf, 0); + + /* Creation data hash */ + tpm_buf_append_u16(&buf, payload->creation_hash_len); + tpm_buf_append(&buf, payload->creation_hash, + payload->creation_hash_len); + + /* signature scheme */ + tpm_buf_append_u16(&buf, TPM_ALG_NULL); + + /* creation ticket */ + tpm_buf_append(&buf, payload->tk, payload->tk_len); + + rc = tpm_send(chip, buf.data, tpm_buf_length(&buf)); + if (rc) + goto out; + + head = (struct tpm_header *)buf.data; + + if (head->return_code != 0) + rc = -EINVAL; +out: + tpm_buf_destroy(&buf); + + return rc; +} + int swsusp_encrypt_digest(struct swsusp_header *header) { const struct cred *cred = current_cred(); @@ -95,7 +186,7 @@ int swsusp_encrypt_digest(struct swsusp_header *header) struct key *key; int ret, i; - char *keyinfo = "new\t32\tkeyhandle=0x81000001"; + char *keyinfo = "new\t32\tkeyhandle=0x81000001\tcreationpcrs=0x00800000"; chip = tpm_default_chip(); @@ -164,6 +255,7 @@ int swsusp_decrypt_digest(struct swsusp_header *header) char *keytemplate = "load\t%s\tkeyhandle=0x81000001"; struct trusted_key_payload *payload; struct tpm_digest *digests = NULL; + char certhash[SHA256_DIGEST_SIZE]; char *blobstring = NULL; char *keyinfo = NULL; struct tpm_chip *chip; @@ -184,8 +276,10 @@ int swsusp_decrypt_digest(struct swsusp_header *header) digests = kcalloc(chip->nr_allocated_banks, sizeof(struct tpm_digest), GFP_KERNEL); - if (!digests) + if (!digests) { + ret = -ENOMEM; goto reset; + } for (i = 0; i <= chip->nr_allocated_banks; i++) { digests[i].alg_id = chip->allocated_banks[i].alg_id; @@ -227,8 +321,58 @@ int swsusp_decrypt_digest(struct swsusp_header *header) payload = key->payload.data[0]; - ret = swsusp_enc_dec(payload, header->digest, 0); + ret = sha256_data(payload->creation, payload->creation_len, certhash); + if (ret < 0) + goto out; + + if (memcmp(payload->creation_hash, certhash, SHA256_DIGEST_SIZE) != 0) { + ret = -EINVAL; + goto out; + } + + ret = tpm_certify_creationdata(chip, payload); + if (ret != 0) { + ret = -EINVAL; + goto out; + } + + /* We now know that the creation data is authentic - parse it */ + + /* TPML_PCR_SELECTION.count */ + if (be32_to_cpu(*(int *)payload->creation) != 1) { + ret = -EINVAL; + goto out; + } + + if (be16_to_cpu(*(u16 *)&payload->creation[4]) != TPM_ALG_SHA256) { + ret = -EINVAL; + goto out; + } + + if (*(char *)&payload->creation[6] != 3) { + ret = -EINVAL; + goto out; + } + + /* PCR 23 selected */ + if (be32_to_cpu(*(int *)&payload->creation[6]) != 0x03000080) { + ret = -EINVAL; + goto out; + } + + if (be16_to_cpu(*(u16 *)&payload->creation[10]) != + SHA256_DIGEST_SIZE) { + ret = -EINVAL; + goto out; + } + if (memcmp(&payload->creation[12], expected_digest, + SHA256_DIGEST_SIZE) != 0) { + ret = -EINVAL; + goto out; + } + + ret = swsusp_enc_dec(payload, header->digest, 0); out: key_revoke(key); key_put(key); -- 2.30.0.617.g56c4b15f3c-goog