From patchwork Mon Oct 23 21:40:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Biggers X-Patchwork-Id: 10023221 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7D28E603FA for ; Mon, 23 Oct 2017 21:43:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6E9D828932 for ; Mon, 23 Oct 2017 21:43:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 637E128938; Mon, 23 Oct 2017 21:43:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D80DD28921 for ; Mon, 23 Oct 2017 21:43:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932230AbdJWVnh (ORCPT ); Mon, 23 Oct 2017 17:43:37 -0400 Received: from mail-io0-f194.google.com ([209.85.223.194]:56950 "EHLO mail-io0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932204AbdJWVmg (ORCPT ); Mon, 23 Oct 2017 17:42:36 -0400 Received: by mail-io0-f194.google.com with SMTP id m81so21686339ioi.13; Mon, 23 Oct 2017 14:42:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/NNjL42227y+17N3q+8JQJQx/GzyIdYSd/kkDs6iCQs=; b=GpF44tTHxdqPPFgMsO1/N/6A0Wx5/j5UD7xqdhn4ZUXV0h89Re7LAZBUlAykdJnQPu dzmRoA7lg77j4TZnUkdteJL52pOy5sbsPMig+H6xLWQNe1tDy1QqBz/PyWRTtMVQvBRz QVS28dNnifcLXJCmq5unqDB7aERIAeXu/J5ifm0K4mCZxpdRycN8Ca52o2Utj+5CEbs3 ZG8zg/FqEHiN7sqrsamcU56sIJodqjZrMEwYC1WtBSFfIQ96SBSx8UF17TCaU5qsW/ux KOOoyl2kDDJ6b41IoW9as1BMJCe1C1a6lGoszy7UtRGPqwYHB9hiJNRSoOEHVHY6zXyK 3vQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/NNjL42227y+17N3q+8JQJQx/GzyIdYSd/kkDs6iCQs=; b=ksunJ8OR1Nwy5pBuJE2EHVGao/H/YrYo6nlW78hwlqk069LYPqIDeePcs2I695VGH6 01FfOHzclQHQD2Ld7um+phFz/Nzk75mJmQOFC8PIICL9dtOsQNUKomsvUREsJDeUOnJV 2syTti2hSUfJ5UwYqmhkWl1kU/GBrOd/p4YxsFj3ZWmVBqUQooiCeqpM2thcJXn8kkQK l5XgrdnsAyGsuQuIZIBGKnh5MHvcDpbsQX8X/hDjshrA9rNyndP5AOUzYHMqQjuaDU0L dKBMWlDJ4pDChNBLEC0vjYfFFiK5wHVH2zK0grnEsBAP7KKRoO0+Xdd6kLIrC1mR3Hw4 /2XA== X-Gm-Message-State: AMCzsaUT2t1dtQ+3QInA3gbAmdJfoDpNKA+NXtfrzLs6+Q/Z/0pR734+ VOsKJhWoA5MB/Oo+3gzSEuKDPjIP X-Google-Smtp-Source: ABhQp+QO1HWbcnv37YJYKloe6q+/CzEmiUuOwCFgWmigS7UXdf47wc089dYilSAnkyQHjKUyZOAjLQ== X-Received: by 10.107.163.15 with SMTP id m15mr18627859ioe.61.1508794953630; Mon, 23 Oct 2017 14:42:33 -0700 (PDT) Received: from ebiggers-linuxstation.kir.corp.google.com ([100.66.175.88]) by smtp.gmail.com with ESMTPSA id i63sm3558482ioi.68.2017.10.23.14.42.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 14:42:33 -0700 (PDT) From: Eric Biggers To: linux-fscrypt@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-mtd@lists.infradead.org, linux-api@vger.kernel.org, keyrings@vger.kernel.org, "Theodore Y . Ts'o" , Jaegeuk Kim , Gwendal Grignou , Ryo Hashimoto , Sarthak Kukreti , Nick Desaulniers , Michael Halcrow , Eric Biggers Subject: [RFC PATCH 18/25] fscrypt: allow adding and removing keys for v2 encryption policies Date: Mon, 23 Oct 2017 14:40:51 -0700 Message-Id: <20171023214058.128121-19-ebiggers3@gmail.com> X-Mailer: git-send-email 2.15.0.rc0.271.g36b669edcc-goog In-Reply-To: <20171023214058.128121-1-ebiggers3@gmail.com> References: <20171023214058.128121-1-ebiggers3@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Eric Biggers Extend the FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY ioctls to support adding and removing keys for use by v2 encryption policies. Keys for v2 encryption policies are identified by a 16-byte "identifier", which is a cryptographic hash of the key, instead of by an 8-byte "descriptor". For FS_IOC_ADD_ENCRYPTION_KEY, the kernel calculates the key identifier and copies it to userspace. Userspace is not allowed to choose the key identifier, since the kernel would have to recalculate it anyway to verify that it is correct. For FS_IOC_REMOVE_ENCRYPTION_KEY, userspace provides the key identifier rather than the key descriptor to identify the key to be removed. For both ioctls, a type field indicates whether the old or new way of specifying keys is being used. A common structure is used, 'struct fscrypt_key_specifier', and it has some extra space just in case we have to introduce a new way to identify keys in the future. Note that keys for v1 and v2 encryption policies are both stored in ->s_master_keys, but their descriptions will be of different lengths. Therefore, they cannot be mixed up when we search for a key. For now the ioctls still always require capable(CAP_SYS_ADMIN). We'll be able to relax that soon, but only for v2 policies. Signed-off-by: Eric Biggers --- fs/crypto/keyinfo.c | 75 ++++++++++++++++++++++++++++++++++++++++---- include/uapi/linux/fscrypt.h | 2 ++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index e9de625ddfe4..c9e7b2b262d2 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -32,6 +32,19 @@ #define HKDF_HMAC_ALG "hmac(sha512)" #define HKDF_HASHLEN SHA512_DIGEST_SIZE +/* + * The list of contexts in which we use HKDF to derive additional keys from a + * master key. The values in this list are used as the first byte of the + * application-specific info string to guarantee that info strings are never + * repeated between contexts. + * + * Keys derived with different info strings are cryptographically isolated from + * each other --- knowledge of one derived key doesn't reveal any others. + * (This property is particularly important for the derived key used as the + * "key identifier", as that is stored in the clear.) + */ +#define HKDF_CONTEXT_KEY_IDENTIFIER 1 + /* * HKDF consists of two steps: * @@ -228,7 +241,12 @@ struct fscrypt_master_key { */ struct fscrypt_master_key_secret mk_secret; - /* Arbitrary key descriptor which was assigned by userspace */ + /* + * For v1 policy keys: an arbitrary key descriptor which was assigned by + * userspace (->descriptor). + * + * For v2 policy keys: a cryptographic hash of this key (->identifier). + */ struct fscrypt_key_specifier mk_spec; /* @@ -252,6 +270,8 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec) switch (spec->type) { case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR: return FSCRYPT_KEY_DESCRIPTOR_SIZE; + case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER: + return FSCRYPT_KEY_IDENTIFIER_SIZE; } return 0; } @@ -346,7 +366,7 @@ static struct key *search_fscrypt_keyring(struct key *keyring, #define FSCRYPT_FS_KEYRING_DESCRIPTION_SIZE \ (sizeof("fscrypt-") - 1 + sizeof(((struct super_block *)0)->s_id) + 1) -#define FSCRYPT_MK_DESCRIPTION_SIZE (2 * FSCRYPT_KEY_DESCRIPTOR_SIZE + 1) +#define FSCRYPT_MK_DESCRIPTION_SIZE (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + 1) static void format_fs_keyring_description( char description[FSCRYPT_FS_KEYRING_DESCRIPTION_SIZE], @@ -550,6 +570,39 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) if (copy_from_user(secret.raw, uarg->raw, secret.size)) goto out_wipe_secret; + if (arg.key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) { + struct crypto_shash *hmac_tfm; + + hmac_tfm = allocate_hmac_tfm(secret.raw, secret.size); + if (IS_ERR(hmac_tfm)) { + err = PTR_ERR(hmac_tfm); + goto out_wipe_secret; + } + + /* + * Hash the master key to get the key identifier, then return it + * to userspace. Specifically, we derive the key identifier + * from the master key with HKDF-SHA512, using a unique + * application-specific info string. This is preferable to a + * simple truncated SHA512 because it means we only ever use the + * master key for a single cryptographic primitive (HKDF-SHA512) + * rather than two (HKDF-SHA512 and SHA512). It *maybe* would + * be okay, but cryptographically it would be bad practice. + */ + err = hkdf_expand(hmac_tfm, HKDF_CONTEXT_KEY_IDENTIFIER, + NULL, 0, arg.key_spec.identifier, + FSCRYPT_KEY_IDENTIFIER_SIZE); + crypto_free_shash(hmac_tfm); + if (err) + goto out_wipe_secret; + + err = -EFAULT; + if (copy_to_user(uarg->key_spec.identifier, + arg.key_spec.identifier, + FSCRYPT_KEY_IDENTIFIER_SIZE)) + goto out_wipe_secret; + } + err = add_master_key(sb, &secret, &arg.key_spec); out_wipe_secret: wipe_master_key_secret(&secret); @@ -872,6 +925,10 @@ static int derive_key_aes(const u8 *master_key, * Search the current task's subscribed keyrings for a "logon" key with * description prefix:descriptor, and if found acquire a read lock on it and * return a pointer to its validated payload in *payload_ret. + * + * This is only used for v1 encryption policies, where keys are identified by + * master_key_descriptor. With newer policy versions, only the filesystem-level + * keyring (->s_master_keys) is supported. */ static struct key * find_and_lock_process_key(const char *prefix, @@ -977,17 +1034,23 @@ static int find_and_derive_key(const struct inode *inode, memcpy(mk_spec.descriptor, ctx->v1.master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE); break; + case FSCRYPT_CONTEXT_V2: + mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER; + memcpy(mk_spec.identifier, ctx->v2.master_key_identifier, + FSCRYPT_KEY_IDENTIFIER_SIZE); + break; default: - return -EOPNOTSUPP; + return -EOPNOTSUPP; /* should have been checked earlier too */ } key = find_master_key(inode->i_sb, &mk_spec); if (IS_ERR(key)) { - if (key != ERR_PTR(-ENOKEY)) + if (key != ERR_PTR(-ENOKEY) || + ctx->v1.version != FSCRYPT_CONTEXT_V1) return PTR_ERR(key); /* - * As a legacy fallback, we search the current task's subscribed - * keyrings in addition to ->s_master_keys. + * As a legacy fallback for v1 policies, we search the current + * task's subscribed keyrings in addition to ->s_master_keys. */ return find_and_derive_key_legacy(inode, &ctx->v1, derived_key, derived_keysize); diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 065060b20a34..1918bdc0c6d7 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -82,10 +82,12 @@ struct fscrypt_get_policy_ex_args { struct fscrypt_key_specifier { __u32 type; #define FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR 1 +#define FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER 2 __u32 reserved; union { __u8 max_specifier[32]; __u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; + __u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; }; };