From patchwork Wed Sep 11 12:28:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800383 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 954AD199926; Wed, 11 Sep 2024 12:29:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057787; cv=none; b=KIWMlIAfYvWcPJLTXol259msG/gj011Y1dWsVNGwN1gEM04mX9nBKQw2W2q0U7SrBCVi6iMsbUK8n/5M1qz32u9pGLDF9CT3O/VG/wGfOaZlZeXPRbbshRqKaGfGr+5J9Der4jdoLq9waxUmxSzfk4OPO2tqH+HKccaPeT7+gF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057787; c=relaxed/simple; bh=zadhMIMAhHYJ1waNtdLmU4A5krbN3rV+oKsxvuPZD4Q=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VzyyX5jIKRPn3vjO+nhrOiIJHW+uv0Snm283dwZEVoFfdzbT+BuYYFL5T5SqbaehOQ2ZB0EqXr/gyTzcaxZhsyHU6yzMB7ZLViInVAJFsUJ1w2+LuFWy+k2IZnY1NcN98ZqJazdFG8x/whIePa8CtJpCzQQj/ppgt2HYahQIZjM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fXP2KMBz9v7Q2; Wed, 11 Sep 2024 20:10:13 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 53315140123; Wed, 11 Sep 2024 20:29:40 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S3; Wed, 11 Sep 2024 13:29:39 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 01/14] mpi: Introduce mpi_key_length() Date: Wed, 11 Sep 2024 14:28:58 +0200 Message-Id: <20240911122911.1381864-2-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S3 X-Coremail-Antispam: 1UD129KBjvJXoW7Aw17KFy3ur47KF1UAFWfAFb_yoW5Jr17pF 4Ykw45JrWkJr1SkFyfC3Z5Ga45C3Wv9F1UKrZrJw17J39IkrnxWFZ7ua4Yva18Gr1xAF1U X3y3WFZ5Crn5ZaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPYb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUGw A2048vs2IY020Ec7CjxVAFwI0_Gr0_Xr1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVWUJVWUCwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4j6F4UM28EF7xvwVC2z280aVCY1x0267AKxVW8 JVW8Jr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx 0E2Ix0cI8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWU JVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7AKxV WUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E 14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIx kGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAF wI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r 4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jehFxU UUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQABsD From: Roberto Sassu Introduce the new function to get the number of bits and bytes from an MPI. Signed-off-by: Roberto Sassu Signed-off-by: David Howells --- include/linux/mpi.h | 2 ++ lib/crypto/mpi/mpicoder.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/include/linux/mpi.h b/include/linux/mpi.h index eb0d1c1db208..a7dd4c9d8120 100644 --- a/include/linux/mpi.h +++ b/include/linux/mpi.h @@ -90,6 +90,8 @@ enum gcry_mpi_format { }; MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes); +int mpi_key_length(const void *xbuffer, unsigned int ret_nread, + unsigned int *nbits_arg, unsigned int *nbytes_arg); MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread); int mpi_fromstr(MPI val, const char *str); MPI mpi_scanval(const char *string); diff --git a/lib/crypto/mpi/mpicoder.c b/lib/crypto/mpi/mpicoder.c index 3cb6bd148fa9..92447a1c8bf9 100644 --- a/lib/crypto/mpi/mpicoder.c +++ b/lib/crypto/mpi/mpicoder.c @@ -79,22 +79,41 @@ MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) } EXPORT_SYMBOL_GPL(mpi_read_raw_data); -MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) +int mpi_key_length(const void *xbuffer, unsigned int ret_nread, + unsigned int *nbits_arg, unsigned int *nbytes_arg) { const uint8_t *buffer = xbuffer; - unsigned int nbits, nbytes; - MPI val; + unsigned int nbits; - if (*ret_nread < 2) - return ERR_PTR(-EINVAL); + if (ret_nread < 2) + return -EINVAL; nbits = buffer[0] << 8 | buffer[1]; if (nbits > MAX_EXTERN_MPI_BITS) { pr_info("MPI: mpi too large (%u bits)\n", nbits); - return ERR_PTR(-EINVAL); + return -EINVAL; } - nbytes = DIV_ROUND_UP(nbits, 8); + if (nbits_arg) + *nbits_arg = nbits; + if (nbytes_arg) + *nbytes_arg = DIV_ROUND_UP(nbits, 8); + + return 0; +} +EXPORT_SYMBOL_GPL(mpi_key_length); + +MPI mpi_read_from_buffer(const void *xbuffer, unsigned int *ret_nread) +{ + const uint8_t *buffer = xbuffer; + unsigned int nbytes; + MPI val; + int ret; + + ret = mpi_key_length(xbuffer, *ret_nread, NULL, &nbytes); + if (ret < 0) + return ERR_PTR(ret); + if (nbytes + 2 > *ret_nread) { pr_info("MPI: mpi larger than buffer nbytes=%u ret_nread=%u\n", nbytes, *ret_nread); From patchwork Wed Sep 11 12:28:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800385 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1906319E963; Wed, 11 Sep 2024 12:29:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057797; cv=none; b=Gv8uDXOMtKnjRnTgwwkwYas+0RcL5otMdeztLFH3aAm1TiPufqEg8+oHrG7tFlLw1G/3RuXw1vMfwlOBO2MhgBwqPbn01Q5F2tQ8YYYdK6VykKSFKYJZoky2fMSFgfsWila2kyFAmPrwUENV3yMzLNkpO6A0UR8GuIEC/sMuN38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057797; c=relaxed/simple; bh=EpGNTRgibJcdtmgo/aEqQhlxB8Z5jcuNDS92VaWwIz8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gz5x2ZURfXHTi4fSSjjK9pIBz0S/OAmxckWVc2iNAkCw1nyvUwKs4V8Rjs9cJOzZhbUoENnWAsVFdr5fB3WkfKdlXcFPgKw4SsEOq754weNQDCEkDF9/ArWbfozXW46XT0S5uvOCZYZDpzJ2ZpEpbqjejgvPEvH1vko201A+E4g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fXc1889z9v7NN; Wed, 11 Sep 2024 20:10:24 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 256A7140418; Wed, 11 Sep 2024 20:29:46 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S4; Wed, 11 Sep 2024 13:29:45 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 02/14] rsa: add parser of raw format Date: Wed, 11 Sep 2024 14:28:59 +0200 Message-Id: <20240911122911.1381864-3-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S4 X-Coremail-Antispam: 1UD129KBjvJXoW3Jr4Dtw1UGryxtFyfAFW3Awb_yoW7try7pF 45G3yrKrWUGFyvyF4ru3WfAw13Jw1fGw4jqFZ3J3sYywsrWryUJa17CF4F9Fy3GrnFvF12 yr4Yg3WY9r1DXaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPYb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUXw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVWUJVWUCwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4j6F4UM28EF7xvwVC2z280aVCY1x0267AKxVW8 JVW8Jr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx 0E2Ix0cI8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWU JVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7AKxV WUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E 14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIx kGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAF wI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r 4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07UCZXrU UUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQACsA From: Roberto Sassu Parse the RSA key with RAW format if the ASN.1 parser returns an error, to avoid passing somehow the key format as parameter. Signed-off-by: Roberto Sassu Signed-off-by: David Howells --- crypto/rsa.c | 14 ++++-- crypto/rsa_helper.c | 83 ++++++++++++++++++++++++++++++++++- include/crypto/internal/rsa.h | 6 +++ 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/crypto/rsa.c b/crypto/rsa.c index d9be9e86097e..66d42974d47d 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -272,8 +272,11 @@ static int rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, rsa_free_mpi_key(mpi_key); ret = rsa_parse_pub_key(&raw_key, key, keylen); - if (ret) - return ret; + if (ret) { + ret = rsa_parse_pub_key_raw(&raw_key, key, keylen); + if (ret) + return ret; + } mpi_key->e = mpi_read_raw_data(raw_key.e, raw_key.e_sz); if (!mpi_key->e) @@ -311,8 +314,11 @@ static int rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, rsa_free_mpi_key(mpi_key); ret = rsa_parse_priv_key(&raw_key, key, keylen); - if (ret) - return ret; + if (ret) { + ret = rsa_parse_priv_key_raw(&raw_key, key, keylen); + if (ret) + return ret; + } mpi_key->d = mpi_read_raw_data(raw_key.d, raw_key.d_sz); if (!mpi_key->d) diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c index 94266f29049c..40a17ebc972f 100644 --- a/crypto/rsa_helper.c +++ b/crypto/rsa_helper.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "rsapubkey.asn1.h" #include "rsaprivkey.asn1.h" @@ -148,6 +149,42 @@ int rsa_get_qinv(void *context, size_t hdrlen, unsigned char tag, return 0; } +typedef int (*rsa_get_func)(void *, size_t, unsigned char, + const void *, size_t); + +static int rsa_parse_key_raw(struct rsa_key *rsa_key, + const void *key, unsigned int key_len, + rsa_get_func *func, int n_func) +{ + unsigned int nbytes, len = key_len; + const void *key_ptr = key; + int ret, i; + + for (i = 0; i < n_func; i++) { + if (key_len < 2) + return -EINVAL; + + ret = mpi_key_length(key_ptr, len, NULL, &nbytes); + if (ret < 0) + return ret; + + key_ptr += 2; + key_len -= 2; + + if (key_len < nbytes) + return -EINVAL; + + ret = func[i](rsa_key, 0, 0, key_ptr, nbytes); + if (ret < 0) + return ret; + + key_ptr += nbytes; + key_len -= nbytes; + } + + return 0; +} + /** * rsa_parse_pub_key() - decodes the BER encoded buffer and stores in the * provided struct rsa_key, pointers to the raw key as is, @@ -157,7 +194,7 @@ int rsa_get_qinv(void *context, size_t hdrlen, unsigned char tag, * @key: key in BER format * @key_len: length of key * - * Return: 0 on success or error code in case of error + * Return: 0 on success or error code in case of error. */ int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len) @@ -166,6 +203,27 @@ int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key, } EXPORT_SYMBOL_GPL(rsa_parse_pub_key); +/** + * rsa_parse_pub_key_raw() - parse the RAW key and store in the provided struct + * rsa_key, pointers to the raw key as is, so that + * the caller can copy it or MPI parse it, etc. + * + * @rsa_key: struct rsa_key key representation + * @key: key in RAW format + * @key_len: length of key + * + * Return: 0 on success or error code in case of error. + */ +int rsa_parse_pub_key_raw(struct rsa_key *rsa_key, const void *key, + unsigned int key_len) +{ + rsa_get_func pub_func[] = {rsa_get_n, rsa_get_e}; + + return rsa_parse_key_raw(rsa_key, key, key_len, + pub_func, ARRAY_SIZE(pub_func)); +} +EXPORT_SYMBOL_GPL(rsa_parse_pub_key_raw); + /** * rsa_parse_priv_key() - decodes the BER encoded buffer and stores in the * provided struct rsa_key, pointers to the raw key @@ -176,7 +234,7 @@ EXPORT_SYMBOL_GPL(rsa_parse_pub_key); * @key: key in BER format * @key_len: length of key * - * Return: 0 on success or error code in case of error + * Return: 0 on success or error code in case of error. */ int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len) @@ -184,3 +242,24 @@ int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, return asn1_ber_decoder(&rsaprivkey_decoder, rsa_key, key, key_len); } EXPORT_SYMBOL_GPL(rsa_parse_priv_key); + +/** + * rsa_parse_priv_key_raw() - parse the RAW key and store in the provided struct + * rsa_key, pointers to the raw key as is, so that + * the caller can copy it or MPI parse it, etc. + * + * @rsa_key: struct rsa_key key representation + * @key: key in RAW format + * @key_len: length of key + * + * Return: 0 on success or error code in case of error. + */ +int rsa_parse_priv_key_raw(struct rsa_key *rsa_key, const void *key, + unsigned int key_len) +{ + rsa_get_func priv_func[] = {rsa_get_n, rsa_get_e, rsa_get_d}; + + return rsa_parse_key_raw(rsa_key, key, key_len, + priv_func, ARRAY_SIZE(priv_func)); +} +EXPORT_SYMBOL_GPL(rsa_parse_priv_key_raw); diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h index e870133f4b77..7141e806ceea 100644 --- a/include/crypto/internal/rsa.h +++ b/include/crypto/internal/rsa.h @@ -50,8 +50,14 @@ struct rsa_key { int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len); +int rsa_parse_pub_key_raw(struct rsa_key *rsa_key, const void *key, + unsigned int key_len); + int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len); +int rsa_parse_priv_key_raw(struct rsa_key *rsa_key, const void *key, + unsigned int key_len); + extern struct crypto_template rsa_pkcs1pad_tmpl; #endif From patchwork Wed Sep 11 12:29:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800386 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout12.his.huawei.com (frasgout12.his.huawei.com [14.137.139.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 37E4918C03E; Wed, 11 Sep 2024 12:29:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057801; cv=none; b=QE2c/5ViQTaSUWN9VEJ/rU6suG/4ELOf0AbjrGT+gq3jNC1g+/IHmjUdeiAQKxJMQmITgz3fqD8hBkgg7q4//qmeeTmGuCHKjFkw/oMvB3TSkWagXMclEeF/7M2HaSQQ51MSF+ouKbxDc14k24/IyDtmbMrStOugpcN7L6vGuG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057801; c=relaxed/simple; bh=B6emJ8PXU8IoHFjTi36zNHukoCT6UB6UryFbbH4zT9w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DAB0XZ1qoxizQr2tBe/Yn0jpKTmIxbc4QlxYHvi9HslVhSeZSIwUNBQL351erb4QnvcGREqMT7WdtUMkpGkmQZ9IZ6o8/A69NstpBIdbKsqkGekaYfRJ89zI/QDQ6IPyKJGu81P031E99Nj6U+ESFwlVtpyyV8Vja7KiG7eodJM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout12.his.huawei.com (SkyGuard) with ESMTP id 4X3fQ44ldHz9v7Jb; Wed, 11 Sep 2024 20:04:44 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 0597A140413; Wed, 11 Sep 2024 20:29:52 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S5; Wed, 11 Sep 2024 13:29:51 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 03/14] PGPLIB: PGP definitions (RFC 9580) Date: Wed, 11 Sep 2024 14:29:00 +0200 Message-Id: <20240911122911.1381864-4-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S5 X-Coremail-Antispam: 1UD129KBjvJXoWxuFWUKFyUGrW5tF1kAFWfGrg_yoWxXr4xpr s5Gr95XFZ8t343tr1aqr4j9a43JrsrArn5Grn3Kw15t3W5WryxW34ktr1kXanrCa98J3yY kFW5Jrn3Cwn0y37anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPYb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUWw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVWUJVWUCwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26r4j6F4UM28EF7xvwVC2z280aVCY1x0267AKxVW8 JVW8Jr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx 0E2Ix0cI8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWU JVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7AKxV WUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E 14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIx kGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAF wI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r 4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07UACztU UUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQADsB From: David Howells Provide some useful PGP definitions from RFC 9580. These describe details of public key crypto as used by crypto keys for things like signature verification. Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/pgp.h | 216 +++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 crypto/asymmetric_keys/pgp.h diff --git a/crypto/asymmetric_keys/pgp.h b/crypto/asymmetric_keys/pgp.h new file mode 100644 index 000000000000..eaf0ab8e0373 --- /dev/null +++ b/crypto/asymmetric_keys/pgp.h @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* PGP definitions (RFC 9580) + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include + +struct pgp_key_ID { + u8 id[8]; +} __packed; + +struct pgp_time { + u8 time[4]; +} __packed; + +/* + * PGP public-key algorithm identifiers [RFC 9580: 9.1] + */ +enum pgp_pubkey_algo { + PGP_PUBKEY_RSA_ENC_OR_SIG = 1, + PGP_PUBKEY_RSA_ENC_ONLY = 2, + PGP_PUBKEY_RSA_SIG_ONLY = 3, + PGP_PUBKEY_ELGAMAL = 16, + PGP_PUBKEY_DSA = 17, + PGP_PUBKEY_ECDH = 18, + PGP_PUBKEY_ECDSA = 19, + PGP_PUBKEY_EDDSA_LEGACY = 22, + PGP_PUBKEY_X25519 = 25, + PGP_PUBKEY_X448 = 26, + PGP_PUBKEY_ED25519 = 27, + PGP_PUBKEY_ED448 = 28, + PGP_PUBKEY__LAST +}; + +/* + * PGP symmetric-key algorithm identifiers [RFC 9580: 9.3] + */ +enum pgp_symkey_algo { + PGP_SYMKEY_PLAINTEXT = 0, + PGP_SYMKEY_IDEA = 1, + PGP_SYMKEY_3DES = 2, + PGP_SYMKEY_CAST5 = 3, + PGP_SYMKEY_BLOWFISH = 4, + PGP_SYMKEY_AES_128KEY = 7, + PGP_SYMKEY_AES_192KEY = 8, + PGP_SYMKEY_AES_256KEY = 9, + PGP_SYMKEY_TWOFISH_256KEY = 10, + PGP_SYMKEY_CAMELIA_128KEY = 11, + PGP_SYMKEY_CAMELIA_192KEY = 12, + PGP_SYMKEY_CAMELIA_256KEY = 13, + PGP_SYMKEY__LAST +}; + +/* + * PGP compression algorithm identifiers [RFC 9580: 9.4] + */ +enum pgp_compr_algo { + PGP_COMPR_UNCOMPRESSED = 0, + PGP_COMPR_ZIP = 1, + PGP_COMPR_ZLIB = 2, + PGP_COMPR_BZIP2 = 3, + PGP_COMPR__LAST +}; + +/* + * PGP hash algorithm identifiers [RFC 9580: 9.4] + */ +enum pgp_hash_algo { + PGP_HASH_MD5 = 1, + PGP_HASH_SHA1 = 2, + PGP_HASH_RIPE_MD_160 = 3, + PGP_HASH_SHA256 = 8, + PGP_HASH_SHA384 = 9, + PGP_HASH_SHA512 = 10, + PGP_HASH_SHA224 = 11, + PGP_HASH_SHA3_256 = 12, + PGP_HASH_SHA3_512 = 14, + PGP_HASH__LAST +}; + +extern const char *const pgp_hash_algorithms[PGP_HASH__LAST]; + +/* + * PGP packet type tags [RFC 9580: 5]. + */ +enum pgp_packet_tag { + PGP_PKT_RESERVED = 0, + PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, + PGP_PKT_SIGNATURE = 2, + PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, + PGP_PKT_ONEPASS_SIGNATURE = 4, + PGP_PKT_SECRET_KEY = 5, + PGP_PKT_PUBLIC_KEY = 6, + PGP_PKT_SECRET_SUBKEY = 7, + PGP_PKT_COMPRESSED_DATA = 8, + PGP_PKT_SYM_ENC_DATA = 9, + PGP_PKT_MARKER = 10, + PGP_PKT_LITERAL_DATA = 11, + PGP_PKT_TRUST = 12, + PGP_PKT_USER_ID = 13, + PGP_PKT_PUBLIC_SUBKEY = 14, + PGP_PKT_USER_ATTRIBUTE = 17, + PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, + PGP_PKT_MODIFY_DETECT_CODE = 19, + PGP_PKT_PRIVATE_0 = 60, + PGP_PKT_PRIVATE_3 = 63, + PGP_PKT__HIGHEST = 63 +}; + +/* + * Signature (tag 2) packet [RFC 9580: 5.2]. + */ +enum pgp_signature_version { + PGP_SIG_VERSION_3 = 3, + PGP_SIG_VERSION_4 = 4, +}; + +/* + * Signature types [RFC 9580: 5.2.1]. + */ +enum pgp_signature_type { + PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, + PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, + PGP_SIG_STANDALONE_SIG = 0x02, + PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, + PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, + PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, + PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, + PGP_SIG_SUBKEY_BINDING_SIG = 0x18, + PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, + PGP_SIG_DIRECTLY_ON_KEY = 0x1F, + PGP_SIG_KEY_REVOCATION_SIG = 0x20, + PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, + PGP_SIG_CERT_REVOCATION_SIG = 0x30, + PGP_SIG_TIMESTAMP_SIG = 0x40, + PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, +}; + +struct pgp_signature_v3_packet { + enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ + u8 length_of_hashed; /* == 5 */ + struct { + enum pgp_signature_type signature_type : 8; + struct pgp_time creation_time; + } __packed hashed; + struct pgp_key_ID issuer; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; +} __packed; + +struct pgp_signature_v4_packet { + enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ + enum pgp_signature_type signature_type : 8; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; +} __packed; + +/* + * V4 signature subpacket types [RFC 9580: 5.2.3.7]. + */ +enum pgp_sig_subpkt_type { + PGP_SIG_CREATION_TIME = 2, + PGP_SIG_EXPIRATION_TIME = 3, + PGP_SIG_EXPORTABLE_CERT = 4, + PGP_SIG_TRUST_SIG = 5, + PGP_SIG_REGEXP = 6, + PGP_SIG_REVOCABLE = 7, + PGP_SIG_KEY_EXPIRATION_TIME = 9, + PGP_SIG_PREF_SYM_ALGO = 11, + PGP_SIG_REVOCATION_KEY = 12, + PGP_SIG_ISSUER = 16, + PGP_SIG_NOTATION_DATA = 20, + PGP_SIG_PREF_HASH_ALGO = 21, + PGP_SIG_PREF_COMPR_ALGO = 22, + PGP_SIG_KEY_SERVER_PREFS = 23, + PGP_SIG_PREF_KEY_SERVER = 24, + PGP_SIG_PRIMARY_USER_ID = 25, + PGP_SIG_POLICY_URI = 26, + PGP_SIG_KEY_FLAGS = 27, + PGP_SIG_SIGNERS_USER_ID = 28, + PGP_SIG_REASON_FOR_REVOCATION = 29, + PGP_SIG_FEATURES = 30, + PGP_SIG_TARGET = 31, + PGP_SIG_EMBEDDED_SIG = 32, + PGP_SIG_ISSUER_FINGERPRINT = 33, + PGP_SIG_INTENDED_RECIPIENT_FINGERPRINT = 35, + PGP_SIG_PREFERRED_AEAD_CIPHERS = 39, + PGP_SIG__LAST +}; + +#define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK 0x80 + +/* + * Key (tag 5, 6, 7 and 14) packet + */ +enum pgp_key_version { + PGP_KEY_VERSION_4 = 4, +}; + +struct pgp_key_v4_packet { + enum pgp_key_version version : 8; + struct pgp_time creation_time; + enum pgp_pubkey_algo pubkey_algo : 8; + u8 key_material[]; +} __packed; + +/* + * Literal Data (tag 11) packet + */ +enum pgp_literal_data_format { + PGP_LIT_FORMAT_BINARY = 0x62, + PGP_LIT_FORMAT_TEXT = 0x74, + PGP_LIT_FORMAT_TEXT_UTF8 = 0x75, +}; From patchwork Wed Sep 11 12:29:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800387 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 990C51A2561; Wed, 11 Sep 2024 12:30:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057809; cv=none; b=U3v4jJ90EwjiRwGOw6dJJqaG++1KQXwNhnrkCv7kE8GIT/OMIVUIZDMLcsQjFVAr8NPL8/61xjDyTwpgPW0suVheCIqGmx6T4ysl0SUV1ambrZ2dsw6tQk++9ksxguFeYheYAEBib4di40UtdId1aSP9VV5GQvebN7Ypja5BQBI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057809; c=relaxed/simple; bh=CgFny+1sMztqzbvRL4Zo6dkUwofJasolokF6RhUK2BU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=d9YvtLQEcEfSeSO0ggjYeDp2C31U3dkKyc3aPdqeCYTQh3u1ztpm0lAgbLL9d+SFNuXEAuZjxCj2qnYixGOM2v3EWC32vcKzbqKQzMN+9oWl0qxvYsZ5NzykzHvOImKWVr5re5XpbxiI4GKwGhCzkfWZl5Nwz/6I4e+HvQV6mms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4X3fXh4Cmdz9v7Hl; Wed, 11 Sep 2024 20:10:28 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id D65C3140123; Wed, 11 Sep 2024 20:29:57 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S6; Wed, 11 Sep 2024 13:29:57 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 04/14] PGPLIB: Basic packet parser Date: Wed, 11 Sep 2024 14:29:01 +0200 Message-Id: <20240911122911.1381864-5-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S6 X-Coremail-Antispam: 1UD129KBjvJXoWxtrW5tFWftw18Zr1DtFyxXwb_yoWfKry3pa 48CryrKa1UGwn2krWrAr17WwsrCr48ZFyagayFvw1jk39FgwnYgrZFkFy0ga48KF4DJ34f urs0gFyY93Z8XrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUJVWUCwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr0_Gr1UM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_Jw0_GFyl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r 43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4j6r4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7I U1aLvJUUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQAEsG From: David Howells Provide a simple parser that extracts the packets from a PGP packet blob and passes the desirous ones to the given processor function: struct pgp_parse_context { u64 types_of_interest; int (*process_packet)(struct pgp_parse_context *context, enum pgp_packet_tag type, u8 headerlen, const u8 *data, size_t datalen); }; int pgp_parse_packets(const u8 *data, size_t datalen, struct pgp_parse_context *ctx); This is configured on with CONFIG_PGP_LIBRARY. Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/Kconfig | 6 + crypto/asymmetric_keys/Makefile | 5 + crypto/asymmetric_keys/pgp_library.c | 262 +++++++++++++++++++++++++++ crypto/asymmetric_keys/pgplib.h | 33 ++++ 4 files changed, 306 insertions(+) create mode 100644 crypto/asymmetric_keys/pgp_library.c create mode 100644 crypto/asymmetric_keys/pgplib.h diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index e1345b8f39f1..8215e3fcd8db 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -103,4 +103,10 @@ config FIPS_SIGNATURE_SELFTEST_ECDSA depends on CRYPTO_SHA256=y || CRYPTO_SHA256=FIPS_SIGNATURE_SELFTEST depends on CRYPTO_ECDSA=y || CRYPTO_ECDSA=FIPS_SIGNATURE_SELFTEST +config PGP_LIBRARY + tristate "PGP parsing library" + help + This option enables a library that provides a number of simple + utility functions for parsing PGP (RFC 9580) packet-based messages. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index bc65d3b98dcb..055b28207111 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -79,3 +79,8 @@ verify_signed_pefile-y := \ $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h + +# +# PGP handling +# +obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o diff --git a/crypto/asymmetric_keys/pgp_library.c b/crypto/asymmetric_keys/pgp_library.c new file mode 100644 index 000000000000..1b87f8af411b --- /dev/null +++ b/crypto/asymmetric_keys/pgp_library.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* PGP packet parser (RFC 9580) + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#define pr_fmt(fmt) "PGPL: "fmt +#include +#include +#include + +#include "pgplib.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PGP library"); + +const char *const pgp_hash_algorithms[PGP_HASH__LAST] = { + [PGP_HASH_MD5] = "md5", + [PGP_HASH_SHA1] = "sha1", + [PGP_HASH_RIPE_MD_160] = "rmd160", + [PGP_HASH_SHA256] = "sha256", + [PGP_HASH_SHA384] = "sha384", + [PGP_HASH_SHA512] = "sha512", + [PGP_HASH_SHA224] = "sha224", + [PGP_HASH_SHA3_256] = "sha3-256", + [PGP_HASH_SHA3_512] = "sha3-512", +}; +EXPORT_SYMBOL_GPL(pgp_hash_algorithms); + +/** + * pgp_parse_packet_header - Parse a PGP packet header + * @_data: Start of the PGP packet (updated to PGP packet data) + * @_datalen: Amount of data remaining in buffer (decreased) + * @_type: Where the packet type will be returned + * @_headerlen: Where the header length will be returned + * + * Parse a set of PGP packet header [RFC 9580: 4.2]. + * + * Return: Packet data size on success; non-zero on error. If successful, + * *_data and *_datalen will have been updated and *_headerlen will be set to + * hold the length of the packet header. + */ +static ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, + enum pgp_packet_tag *_type, + u8 *_headerlen) +{ + enum pgp_packet_tag type; + const u8 *data = *_data; + size_t size, datalen = *_datalen; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 2) + goto short_packet; + + pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); + + type = *data++; + datalen--; + if (!(type & 0x80)) { + pr_debug("Packet type does not have MSB set\n"); + return -EBADMSG; + } + type &= ~0x80; + + if (type & 0x40) { + /* New packet length format */ + type &= ~0x40; + pr_devel("new format: t=%u\n", type); + switch (data[0]) { + case 0x00 ... 0xbf: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + *_headerlen = 2; + break; + case 0xc0 ... 0xdf: + /* Two-byte length */ + if (datalen < 2) + goto short_packet; + size = (data[0] - 192) * 256; + size += data[1] + 192; + data += 2; + datalen -= 2; + *_headerlen = 3; + break; + case 0xff: + /* Five-byte length */ + if (datalen < 5) + goto short_packet; + size = data[1] << 24; + size |= data[2] << 16; + size |= data[3] << 8; + size |= data[4]; + data += 5; + datalen -= 5; + *_headerlen = 6; + break; + default: + pr_debug("Partial body length packet not supported\n"); + return -EBADMSG; + } + } else { + /* Old packet length format */ + u8 length_type = type & 0x03; + + type >>= 2; + pr_devel("old format: t=%u lt=%u\n", type, length_type); + + switch (length_type) { + case 0: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + *_headerlen = 2; + break; + case 1: + /* Two-byte length */ + if (datalen < 2) + goto short_packet; + size = data[0] << 8; + size |= data[1]; + data += 2; + datalen -= 2; + *_headerlen = 3; + break; + case 2: + /* Four-byte length */ + if (datalen < 4) + goto short_packet; + size = data[0] << 24; + size |= data[1] << 16; + size |= data[2] << 8; + size |= data[3]; + data += 4; + datalen -= 4; + *_headerlen = 5; + break; + default: + pr_debug("Indefinite length packet not supported\n"); + return -EBADMSG; + } + } + + pr_devel("datalen=%zu size=%zu\n", datalen, size); + if (datalen < size) + goto short_packet; + if (size > INT_MAX) + goto too_big; + + *_data = data; + *_datalen = datalen; + *_type = type; + pr_devel("Found packet type=%u size=%zd\n", type, size); + return size; + +short_packet: + pr_debug("Attempt to parse short packet\n"); + return -EBADMSG; +too_big: + pr_debug("Signature subpacket size >2G\n"); + return -EMSGSIZE; +} + +/** + * pgp_parse_packets - Parse a set of PGP packets + * @data: Data to be parsed (updated) + * @datalen: Amount of data (updated) + * @ctx: Parsing context + * + * Parse a set of PGP packets [RFC 9580: 4]. + * + * Return: 0 on successful parsing, a negative value otherwise. + */ +int pgp_parse_packets(const u8 *data, size_t datalen, + struct pgp_parse_context *ctx) +{ + enum pgp_packet_tag type; + ssize_t pktlen; + u8 headerlen; + int ret; + + while (datalen > 2) { + pktlen = pgp_parse_packet_header(&data, &datalen, &type, + &headerlen); + if (pktlen < 0) + return pktlen; + + if ((ctx->types_of_interest >> type) & 1) { + ret = ctx->process_packet(ctx, type, headerlen, + data, pktlen); + if (ret < 0) + return ret; + } + data += pktlen; + datalen -= pktlen; + } + + if (datalen != 0) { + pr_debug("Excess octets in packet stream\n"); + return -EBADMSG; + } + + return 0; +} +EXPORT_SYMBOL_GPL(pgp_parse_packets); + +/** + * pgp_parse_public_key - Parse the common part of a PGP pubkey packet + * @_data: Content of packet (updated) + * @_datalen: Length of packet remaining (updated) + * @pk: Public key data + * + * Parse the common data struct for a PGP pubkey packet [RFC 9580: 5.5.2]. + * + * Return: 0 on successful parsing, a negative value otherwise. + */ +int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + struct pgp_parse_pubkey *pk) +{ + const u8 *data = *_data; + size_t datalen = *_datalen; + unsigned int tmp; + + if (datalen < 12) { + pr_debug("Public key packet too short\n"); + return -EBADMSG; + } + + pk->version = *data++; + switch (pk->version) { + case PGP_KEY_VERSION_4: + break; + default: + pr_debug("Public key packet with unhandled version %d\n", + pk->version); + return -EBADMSG; + } + + tmp = *data++ << 24; + tmp |= *data++ << 16; + tmp |= *data++ << 8; + tmp |= *data++; + pk->creation_time = tmp; + if (pk->version == PGP_KEY_VERSION_4) + pk->expires_at = 0; /* Have to get it from the selfsignature */ + + pk->pubkey_algo = *data++; + datalen -= 6; + + pr_devel("%x,%x,%lx,%lx\n", + pk->version, pk->pubkey_algo, pk->creation_time, + pk->expires_at); + + *_data = data; + *_datalen = datalen; + return 0; +} +EXPORT_SYMBOL_GPL(pgp_parse_public_key); diff --git a/crypto/asymmetric_keys/pgplib.h b/crypto/asymmetric_keys/pgplib.h new file mode 100644 index 000000000000..3ec4b408a11e --- /dev/null +++ b/crypto/asymmetric_keys/pgplib.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* PGP library definitions (RFC 9580) + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include "pgp.h" + +/* + * PGP library packet parser + */ +struct pgp_parse_context { + u64 types_of_interest; + int (*process_packet)(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen); +}; + +extern int pgp_parse_packets(const u8 *data, size_t datalen, + struct pgp_parse_context *ctx); + +struct pgp_parse_pubkey { + enum pgp_key_version version : 8; + enum pgp_pubkey_algo pubkey_algo : 8; + __kernel_old_time_t creation_time; + __kernel_old_time_t expires_at; +}; + +extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + struct pgp_parse_pubkey *pk); From patchwork Wed Sep 11 12:29:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800388 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FEED1885B0; Wed, 11 Sep 2024 12:30:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057815; cv=none; b=QOEU0rgmZN5SCbhc8phjZ0lT9suuIpk100EtMvnBz9YVsHjrApaw5xdhWhi34w2/UraZQTBvI6B173bCTfoPAvEAsROgN23dtA/Z9g1G+x/SH0hZ1VEpOg2wKzMY9vcUdLarLOuOeOmmxyhYvqXXLJJ5QeTv0D2uOgiRB9ooy5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057815; c=relaxed/simple; bh=fhV7NqXF8wDIS3ft1+SUHhDw/x5Ya402ySo8Gw3kCqs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jyq0VDgWNFSj1fQ6UK/ioRL/QDWUx+vjkfwlcE70KMCwtf/Ro1JGXuBLV372dOHUT57joW/KsxWPSLaRaHf+6nHqU3l0hZ2uAqxNFPBFIlgzrjATRtp0Bb7qdijQqO3kX3OkgMUtHwCbV10NEighVcdpOpRLv+kL6Jl3PXZKs5E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4X3fXw1W6pz9v7Hm; Wed, 11 Sep 2024 20:10:40 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id BD5FB140B21; Wed, 11 Sep 2024 20:30:03 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S7; Wed, 11 Sep 2024 13:30:03 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 05/14] PGPLIB: Signature parser Date: Wed, 11 Sep 2024 14:29:02 +0200 Message-Id: <20240911122911.1381864-6-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S7 X-Coremail-Antispam: 1UD129KBjvJXoWxuFW8tryruF45Cw1rJr48tFb_yoWDGryfpa 4Iy34fKrWUG3ZavrW8Ar47X3y5Cr40yry7Ga9Yq3WYy39agrn8ZrZ2kFyFkF98t3Z5X3yx CrZ8ta98ur4kZw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPSb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr0_Gr1UM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Y z7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7CjxVAaw2 AFwI0_Jw0_GFyl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAq x4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r 43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7IYx2IY6xkF 7I0E14v26F4j6r4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7I U1aLvJUUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQAFsH From: David Howells Provide some PGP signature parsing helpers: (1) A function to parse V4 signature subpackets and pass the desired ones to a processor function: int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, struct pgp_parse_sig_context *ctx); (2) A function to parse out basic signature parameters from any PGP signature such that the algorithms and public key can be selected: int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, struct pgp_sig_parameters *p); Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/pgp_library.c | 284 +++++++++++++++++++++++++++ crypto/asymmetric_keys/pgplib.h | 25 +++ 2 files changed, 309 insertions(+) diff --git a/crypto/asymmetric_keys/pgp_library.c b/crypto/asymmetric_keys/pgp_library.c index 1b87f8af411b..a9708ccbcb81 100644 --- a/crypto/asymmetric_keys/pgp_library.c +++ b/crypto/asymmetric_keys/pgp_library.c @@ -260,3 +260,287 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen, return 0; } EXPORT_SYMBOL_GPL(pgp_parse_public_key); + +/** + * pgp_parse_sig_subpkt_header - Parse a PGP V4 signature subpacket header + * @_data: Start of the subpacket (updated to subpacket data) + * @_datalen: Amount of data remaining in buffer (decreased) + * @_type: Where the subpacket type will be returned + * + * Parse a PGP V4 signature subpacket header [RFC 9580: 5.2.3.7]. + * + * Return: packet data size on success; non-zero on error. If successful, + * *_data and *_datalen will have been updated and *_headerlen will be set to + * hold the length of the packet header. + */ +static ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, + enum pgp_sig_subpkt_type *_type) +{ + enum pgp_sig_subpkt_type type; + const u8 *data = *_data; + size_t size, datalen = *_datalen; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 2) + goto short_subpacket; + + pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); + + switch (data[0]) { + case 0x00 ... 0xbf: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + break; + case 0xc0 ... 0xfe: + /* Two-byte length */ + if (datalen < 3) + goto short_subpacket; + size = (data[0] - 192) * 256; + size += data[1] + 192; + data += 2; + datalen -= 2; + break; + case 0xff: + if (datalen < 6) + goto short_subpacket; + size = data[1] << 24; + size |= data[2] << 16; + size |= data[3] << 8; + size |= data[4]; + data += 5; + datalen -= 5; + break; + } + + /* The type octet is included in the size */ + pr_devel("datalen=%zu size=%zu\n", datalen, size); + if (datalen < size) + goto short_subpacket; + if (size == 0) + goto very_short_subpacket; + if (size > INT_MAX) + goto too_big; + + type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; + datalen--; + size--; + + *_data = data; + *_datalen = datalen; + *_type = type; + pr_devel("Found subpkt type=%u size=%zd\n", type, size); + return size; + +very_short_subpacket: + pr_debug("Signature subpacket size can't be zero\n"); + return -EBADMSG; +short_subpacket: + pr_debug("Attempt to parse short signature subpacket\n"); + return -EBADMSG; +too_big: + pr_debug("Signature subpacket size >2G\n"); + return -EMSGSIZE; +} + +/** + * pgp_parse_sig_subpkts - Parse a set of PGP V4 signatute subpackets + * @data: Data to be parsed (updated) + * @datalen: Amount of data (updated) + * @ctx: Parsing context + * + * Parse a set of PGP signature subpackets [RFC 9580: 5.2.3]. + * + * Return: 0 on successful parsing, an error value otherwise. + */ +static int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, + struct pgp_parse_sig_context *ctx) +{ + enum pgp_sig_subpkt_type type; + ssize_t pktlen; + int ret; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + while (datalen > 2) { + pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); + if (pktlen < 0) + return pktlen; + if (test_bit(type, ctx->types_of_interest)) { + ret = ctx->process_packet(ctx, type, data, pktlen); + if (ret < 0) + return ret; + } + data += pktlen; + datalen -= pktlen; + } + + if (datalen != 0) { + pr_debug("Excess octets in signature subpacket stream\n"); + return -EBADMSG; + } + + return 0; +} + +struct pgp_parse_sig_params_ctx { + struct pgp_parse_sig_context base; + struct pgp_sig_parameters *params; + bool got_the_issuer; +}; + +/* + * Process a V4 signature subpacket. + */ +static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, + enum pgp_sig_subpkt_type type, + const u8 *data, + size_t datalen) +{ + struct pgp_parse_sig_params_ctx *ctx = + container_of(context, struct pgp_parse_sig_params_ctx, base); + + if (ctx->got_the_issuer) { + pr_debug("V4 signature packet has multiple issuers\n"); + return -EBADMSG; + } + + if (datalen != 8) { + pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", + datalen); + return -EBADMSG; + } + + memcpy(&ctx->params->issuer, data, 8); + ctx->got_the_issuer = true; + return 0; +} + +/** + * pgp_parse_sig_params - Parse basic parameters from a PGP signature packet + * @_data: Content of packet (updated) + * @_datalen: Length of packet remaining (updated) + * @p: The basic parameters + * + * Parse the basic parameters from a PGP signature packet [RFC 9580: 5.2] that + * are needed to start off a signature verification operation. The only ones + * actually necessary are the signature type (which affects how the data is + * transformed) and the hash algorithm. + * + * We also extract the public key algorithm and the issuer's key ID as we'll + * need those to determine if we actually have the public key available. If + * not, then we can't verify the signature anyway. + * + * Return: 0 if successful or a negative error code. *_data and *_datalen are + * updated to point to the 16-bit subset of the hash value and the set of MPIs. + */ +int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + struct pgp_sig_parameters *p) +{ + const u8 *data = *_data; + size_t datalen = *_datalen; + int ret; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 1) + return -EBADMSG; + p->version = *data; + + if (p->version == PGP_SIG_VERSION_3) { + const struct pgp_signature_v3_packet *v3 = (const void *)data; + + if (datalen < sizeof(*v3)) { + pr_debug("Short V3 signature packet\n"); + return -EBADMSG; + } + datalen -= sizeof(*v3); + data += sizeof(*v3); + + /* V3 has everything we need in the header */ + p->signature_type = v3->hashed.signature_type; + memcpy(&p->issuer, &v3->issuer, 8); + p->pubkey_algo = v3->pubkey_algo; + p->hash_algo = v3->hash_algo; + + } else if (p->version == PGP_SIG_VERSION_4) { + const struct pgp_signature_v4_packet *v4 = (const void *)data; + struct pgp_parse_sig_params_ctx ctx = { + .base.process_packet = pgp_process_sig_params_subpkt, + .params = p, + .got_the_issuer = false, + }; + size_t subdatalen; + + if (datalen < sizeof(*v4) + 2 + 2 + 2) { + pr_debug("Short V4 signature packet\n"); + return -EBADMSG; + } + datalen -= sizeof(*v4); + data += sizeof(*v4); + + /* V4 has most things in the header... */ + p->signature_type = v4->signature_type; + p->pubkey_algo = v4->pubkey_algo; + p->hash_algo = v4->hash_algo; + + /* + * ... but we have to get the key ID from the subpackets, of + * which there are two sets. + */ + __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); + + subdatalen = *data++ << 8; + subdatalen |= *data++; + datalen -= 2; + if (subdatalen) { + /* Hashed subpackets */ + pr_devel("hashed data: %zu (after %zu)\n", + subdatalen, sizeof(*v4)); + if (subdatalen > datalen + 2 + 2) { + pr_debug("Short V4 signature packet [hdata]\n"); + return -EBADMSG; + } + ret = pgp_parse_sig_subpkts(data, subdatalen, + &ctx.base); + if (ret < 0) + return ret; + data += subdatalen; + datalen -= subdatalen; + } + + subdatalen = *data++ << 8; + subdatalen |= *data++; + datalen -= 2; + if (subdatalen) { + /* Unhashed subpackets */ + pr_devel("unhashed data: %zu\n", subdatalen); + if (subdatalen > datalen + 2) { + pr_debug("Short V4 signature packet [udata]\n"); + return -EBADMSG; + } + ret = pgp_parse_sig_subpkts(data, subdatalen, + &ctx.base); + if (ret < 0) + return ret; + data += subdatalen; + datalen -= subdatalen; + } + + if (!ctx.got_the_issuer) { + pr_debug("V4 signature packet lacks issuer\n"); + return -EBADMSG; + } + } else { + pr_debug("Signature packet with unhandled version %d\n", + p->version); + return -EBADMSG; + } + + *_data = data; + *_datalen = datalen; + return 0; +} +EXPORT_SYMBOL_GPL(pgp_parse_sig_params); diff --git a/crypto/asymmetric_keys/pgplib.h b/crypto/asymmetric_keys/pgplib.h index 3ec4b408a11e..25191cea33a4 100644 --- a/crypto/asymmetric_keys/pgplib.h +++ b/crypto/asymmetric_keys/pgplib.h @@ -31,3 +31,28 @@ struct pgp_parse_pubkey { extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, struct pgp_parse_pubkey *pk); + +struct pgp_parse_sig_context { + unsigned long types_of_interest[128 / BITS_PER_LONG]; + int (*process_packet)(struct pgp_parse_sig_context *context, + enum pgp_sig_subpkt_type type, + const u8 *data, + size_t datalen); +}; + +extern int pgp_parse_sig_packets(const u8 *data, size_t datalen, + struct pgp_parse_sig_context *ctx); + +struct pgp_sig_parameters { + enum pgp_signature_version version : 8; + enum pgp_signature_type signature_type : 8; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; + union { + struct pgp_key_ID issuer; + __be32 issuer32[2]; + }; +}; + +extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + struct pgp_sig_parameters *p); From patchwork Wed Sep 11 12:29:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800389 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout12.his.huawei.com (frasgout12.his.huawei.com [14.137.139.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC77A192B78; Wed, 11 Sep 2024 12:30:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057824; cv=none; b=ep8qJV/sRsxVt1v/lf78LfebBRx+LSUjnJro1RZr0/WKx47sHF0wJr9KHwQ6MJqzPYRdF4issQGUiCWVgg2xJmVWagYvJCCD/XYhzzdM0LF05G128lZUMPTysVFcvatXsG9oc4+kCm3xYBO4z3oQN1iocJNvz6nPJvZXqVXGQRE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057824; c=relaxed/simple; bh=AngZno8N41cMJowi+55kUrIQRWN72YhfLpSY0OqrLWM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nqsiQuIbXbv/zZDhYFDb1gb/gr4Ilk272E3/2dvQ6juEA+aGDJzLhXHmZbO6CpTdvkNuzF+OaK9YWc3dTTvtnRhoBW+MNzf+2SErsyQUWumzl2DEoUH1Sm/yjSHzIhu4SrzJP2hlLIKg5u0MmpvBOFixrUF/Dbf8F1gSrwrZVRs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout12.his.huawei.com (SkyGuard) with ESMTP id 4X3fQW1zymz9v7JM; Wed, 11 Sep 2024 20:05:07 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 9F4EF1404A8; Wed, 11 Sep 2024 20:30:09 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S8; Wed, 11 Sep 2024 13:30:09 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 06/14] KEYS: PGP data parser Date: Wed, 11 Sep 2024 14:29:03 +0200 Message-Id: <20240911122911.1381864-7-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S8 X-Coremail-Antispam: 1UD129KBjvJXoW3KrW7XryfCr47Zw4kJF1rtFb_yoWkKw1fpa 1rWrWUtrW8GF1SkrWfAFWxKas0yry0yFWag3ySy3Way39Iqr10k34Ikr4UuF9rtF4kJrW3 KFsYvFyjyr1DJ37anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPqb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr1j6F4UJwAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I 80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCj c4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4IIrI8v6xkF7I0E8cxan2IY04v7MxkF7I0En4 kS14v26r1q6r43MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E 5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtV W8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY 1x0267AKxVWxJVW8Jr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14 v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x 07UZTmfUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQAGsE From: David Howells Implement a PGP data parser for the crypto key type to use when instantiating a key. This parser attempts to parse the instantiation data as a PGP packet sequence (RFC 9580), v4 keys only, and if it parses okay attempts to extract a public-key algorithm key or subkey from it. If it finds such a key, it will set up a public_key subtype payload with appropriate handler routines (RSA) and attach it to the key. Thanks to Tetsuo Handa for pointing out some errors. Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/Kconfig | 10 + crypto/asymmetric_keys/Makefile | 4 + crypto/asymmetric_keys/pgp_parser.h | 18 ++ crypto/asymmetric_keys/pgp_public_key.c | 356 ++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 crypto/asymmetric_keys/pgp_parser.h create mode 100644 crypto/asymmetric_keys/pgp_public_key.c diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 8215e3fcd8db..c69bfdc022c0 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -109,4 +109,14 @@ config PGP_LIBRARY This option enables a library that provides a number of simple utility functions for parsing PGP (RFC 9580) packet-based messages. +config PGP_KEY_PARSER + tristate "PGP key parser" + depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select PGP_LIBRARY + select SHA1 # V4 fingerprint generation + help + This option provides support for parsing PGP (RFC 9880) format blobs + for key data and provides the ability to instantiate a crypto key + from a public key packet found inside the blob. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 055b28207111..d197e8b23b83 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -84,3 +84,7 @@ $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h # PGP handling # obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o + +obj-$(CONFIG_PGP_KEY_PARSER) += pgp_key_parser.o +pgp_key_parser-y := \ + pgp_public_key.o diff --git a/crypto/asymmetric_keys/pgp_parser.h b/crypto/asymmetric_keys/pgp_parser.h new file mode 100644 index 000000000000..900f81f5ee14 --- /dev/null +++ b/crypto/asymmetric_keys/pgp_parser.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* PGP crypto data parser internal definitions + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include "pgplib.h" + +#define kenter(FMT, ...) \ + pr_devel("==> %s(" FMT ")\n", __func__, ##__VA_ARGS__) +#define kleave(FMT, ...) \ + pr_devel("<== %s()" FMT "\n", __func__, ##__VA_ARGS__) + +/* + * pgp_public_key.c + */ +extern const char *pgp_to_public_key_algo[PGP_PUBKEY__LAST]; diff --git a/crypto/asymmetric_keys/pgp_public_key.c b/crypto/asymmetric_keys/pgp_public_key.c new file mode 100644 index 000000000000..94284a78bf9b --- /dev/null +++ b/crypto/asymmetric_keys/pgp_public_key.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Instantiate a public key crypto key from PGP format data [RFC 9580] + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#define pr_fmt(fmt) "PGP: "fmt +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pgp_parser.h" + +#define MAX_MPI 5 +#define KEYCTL_SUPPORTS_ENCDEC \ + (KEYCTL_SUPPORTS_ENCRYPT | KEYCTL_SUPPORTS_DECRYPT) +#define KEYCTL_SUPPORTS_SIGVER (KEYCTL_SUPPORTS_SIGN | KEYCTL_SUPPORTS_VERIFY) + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PGP key parser"); + +const char *pgp_to_public_key_algo[PGP_PUBKEY__LAST] = { + [PGP_PUBKEY_RSA_ENC_OR_SIG] = "rsa", + [PGP_PUBKEY_RSA_ENC_ONLY] = "rsa", + [PGP_PUBKEY_RSA_SIG_ONLY] = "rsa", +}; + +static const int pgp_key_algo_p_num_mpi[PGP_PUBKEY__LAST] = { + [PGP_PUBKEY_RSA_ENC_OR_SIG] = 2, + [PGP_PUBKEY_RSA_ENC_ONLY] = 2, + [PGP_PUBKEY_RSA_SIG_ONLY] = 2, +}; + +static const u8 pgp_public_key_capabilities[PGP_PUBKEY__LAST] = { + [PGP_PUBKEY_RSA_ENC_OR_SIG] = KEYCTL_SUPPORTS_ENCDEC | + KEYCTL_SUPPORTS_SIGVER, + [PGP_PUBKEY_RSA_ENC_ONLY] = KEYCTL_SUPPORTS_ENCDEC, + [PGP_PUBKEY_RSA_SIG_ONLY] = KEYCTL_SUPPORTS_SIGVER, +}; + +static inline void digest_putc(struct shash_desc *digest, uint8_t ch) +{ + crypto_shash_update(digest, &ch, 1); +} + +struct pgp_key_data_parse_context { + struct pgp_parse_context pgp; + struct public_key *pub; + u8 raw_fingerprint[HASH_MAX_DIGESTSIZE]; + size_t raw_fingerprint_len; +}; + +/* + * Calculate the public key ID (RFC 9580 5.5.4) + */ +static int pgp_calc_pkey_keyid(struct shash_desc *digest, + struct pgp_parse_pubkey *pgp, + struct public_key *pub) +{ + unsigned int nb[MAX_MPI]; + unsigned int nn[MAX_MPI]; + unsigned int n; + size_t keylen = pub->keylen; + u8 *key_ptr = pub->key; + u8 *pp[MAX_MPI]; + u32 a32; + int npkey = pgp_key_algo_p_num_mpi[pgp->pubkey_algo]; + int i, ret; + + kenter(""); + + n = 6; + for (i = 0; i < npkey; i++) { + if (keylen < 2) + break; + + ret = mpi_key_length(key_ptr, keylen, nb + i, nn + i); + if (ret < 0) + return ret; + + key_ptr += 2; + keylen -= 2; + n += 2; + + if (keylen < nn[i]) + break; + + pp[i] = key_ptr; + key_ptr += nn[i]; + keylen -= nn[i]; + n += nn[i]; + } + + if (keylen != 0) { + pr_debug("excess %zu\n", keylen); + return -EBADMSG; + } + + digest_putc(digest, 0x99); /* ctb */ + digest_putc(digest, n >> 8); /* 16-bit header length */ + digest_putc(digest, n); + digest_putc(digest, pgp->version); + + a32 = pgp->creation_time; + digest_putc(digest, a32 >> 24); + digest_putc(digest, a32 >> 16); + digest_putc(digest, a32 >> 8); + digest_putc(digest, a32 >> 0); + + digest_putc(digest, pgp->pubkey_algo); + + for (i = 0; i < npkey; i++) { + digest_putc(digest, nb[i] >> 8); + digest_putc(digest, nb[i]); + crypto_shash_update(digest, pp[i], nn[i]); + } + ret = 0; + + kleave(" = %d", ret); + return ret; +} + +/* + * Calculate the public key ID fingerprint + */ +static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx, + struct pgp_parse_pubkey *pgp, + struct public_key *pub) +{ + struct crypto_shash *tfm; + struct shash_desc *digest; + char fingerprint[HASH_MAX_DIGESTSIZE * 2 + 1] = { 0 }; + size_t offset; + int ret; + + ret = -ENOMEM; + tfm = crypto_alloc_shash("sha1", 0, 0); + if (IS_ERR(tfm)) + goto cleanup; + + digest = kmalloc(sizeof(*digest) + crypto_shash_descsize(tfm), + GFP_KERNEL); + if (!digest) + goto cleanup_tfm; + + digest->tfm = tfm; + crypto_shash_set_flags(digest->tfm, CRYPTO_TFM_REQ_MAY_SLEEP); + ret = crypto_shash_init(digest); + if (ret < 0) + goto cleanup_hash; + + ret = pgp_calc_pkey_keyid(digest, pgp, pub); + if (ret < 0) + goto cleanup_hash; + + ctx->raw_fingerprint_len = crypto_shash_digestsize(tfm); + + ret = crypto_shash_final(digest, ctx->raw_fingerprint); + if (ret < 0) + goto cleanup_hash; + + offset = ctx->raw_fingerprint_len - 8; + pr_debug("offset %zu/%zu\n", offset, ctx->raw_fingerprint_len); + + bin2hex(fingerprint, ctx->raw_fingerprint, ctx->raw_fingerprint_len); + pr_debug("fingerprint %s\n", fingerprint); + + ret = 0; +cleanup_hash: + kfree(digest); +cleanup_tfm: + crypto_free_shash(tfm); +cleanup: + kleave(" = %d", ret); + return ret; +} + +/* + * Extract a public key or public subkey from the PGP stream. + */ +static int pgp_process_public_key(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen) +{ + const char *algo; + struct pgp_key_data_parse_context *ctx = + container_of(context, struct pgp_key_data_parse_context, pgp); + struct pgp_parse_pubkey pgp; + struct public_key *pub; + u8 capabilities; + int ret; + + kenter(",%u,%u,,%zu", type, headerlen, datalen); + + if (ctx->raw_fingerprint_len) { + kleave(" = -ENOKEY [already]"); + return -EBADMSG; + } + + pub = kzalloc(sizeof(*pub), GFP_KERNEL); + if (!pub) + return -ENOMEM; + pub->id_type = "PGP"; + + ret = pgp_parse_public_key(&data, &datalen, &pgp); + if (ret < 0) + goto cleanup; + + if (pgp.pubkey_algo >= PGP_PUBKEY__LAST) + goto cleanup_unsupported_pkey_algo; + algo = pgp_to_public_key_algo[pgp.pubkey_algo]; + if (!algo) + goto cleanup_unsupported_pkey_algo; + + pub->pkey_algo = algo; + + /* + * It's the public half of a key, so that only gives us encrypt and + * verify capabilities. + */ + capabilities = pgp_public_key_capabilities[pgp.pubkey_algo] & + (KEYCTL_SUPPORTS_ENCRYPT | KEYCTL_SUPPORTS_VERIFY); + /* + * Capabilities are not stored anymore in the public key, consider + * only keys that allow signature verification. + */ + if (!(capabilities & KEYCTL_SUPPORTS_VERIFY)) + goto cleanup_unsupported_pkey_algo; + + pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG; + + pub->key = kmemdup(data, datalen, GFP_KERNEL); + if (!pub->key) + goto cleanup_nomem; + + pub->keylen = datalen; + + ret = pgp_generate_fingerprint(ctx, &pgp, pub); + if (ret < 0) + goto cleanup; + + ctx->pub = pub; + kleave(" = 0 [use]"); + return 0; + +cleanup_unsupported_pkey_algo: + pr_debug("Unsupported public key algorithm %u\n", + pgp.pubkey_algo); + ret = -ENOPKG; + goto cleanup; +cleanup_nomem: + ret = -ENOMEM; + goto cleanup; +cleanup: + pr_devel("cleanup"); + public_key_free(pub); + kleave(" = %d", ret); + return ret; +} + +static struct asymmetric_key_ids * +pgp_key_generate_id(struct pgp_key_data_parse_context *ctx) +{ + struct asymmetric_key_ids *kids; + struct asymmetric_key_id *kid; + + kids = kzalloc(sizeof(*kids), GFP_KERNEL); + if (!kids) + return kids; + + kid = asymmetric_key_generate_id(ctx->raw_fingerprint, + ctx->raw_fingerprint_len, NULL, 0); + if (IS_ERR(kid)) + goto error; + + kids->id[0] = kid; + kids->id[1] = kmemdup(kid, sizeof(*kid) + ctx->raw_fingerprint_len, + GFP_KERNEL); + if (!kids->id[1]) + goto error; + + return kids; +error: + kfree(kids->id[0]); + kfree(kids); + + return NULL; +} + +/* + * Attempt to parse the instantiation data blob for a key as a PGP packet + * message holding a key. + */ +static int pgp_key_parse(struct key_preparsed_payload *prep) +{ + struct pgp_key_data_parse_context ctx; + int ret; + + kenter(""); + + memset(&ctx, 0, sizeof(ctx)); + ctx.pgp.types_of_interest = (1 << PGP_PKT_PUBLIC_KEY); + ctx.pgp.process_packet = pgp_process_public_key; + + ret = pgp_parse_packets(prep->data, prep->datalen, &ctx.pgp); + if (ret < 0) + goto error; + + /* Key packet not found. */ + if (!ctx.raw_fingerprint_len) { + ret = -ENOENT; + goto error; + } + + /* We're pinning the module by being linked against it */ + __module_get(public_key_subtype.owner); + prep->payload.data[asym_subtype] = &public_key_subtype; + prep->payload.data[asym_key_ids] = pgp_key_generate_id(&ctx); + prep->payload.data[asym_crypto] = ctx.pub; + prep->quotalen = 100; + return 0; + +error: + public_key_free(ctx.pub); + return ret; +} + +static struct asymmetric_key_parser pgp_key_parser = { + .owner = THIS_MODULE, + .name = "pgp", + .parse = pgp_key_parse, +}; + +/* + * Module stuff + */ +static int __init pgp_key_init(void) +{ + return register_asymmetric_key_parser(&pgp_key_parser); +} + +static void __exit pgp_key_exit(void) +{ + unregister_asymmetric_key_parser(&pgp_key_parser); +} + +module_init(pgp_key_init); +module_exit(pgp_key_exit); From patchwork Wed Sep 11 12:29:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800390 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4FC217C230; Wed, 11 Sep 2024 12:30:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057826; cv=none; b=sOu5z2V+l73lVRrkANkRNnV7x30ZLOQoGV2YjiOf1XxDxf6bACS0nrbVrWHyyXRU+OjOAFwwJ3M0pH65Sb+r1OpXSYkGnQ0yOkRj49TR37aO03GJYeg/yfM+o5xI+72R0b9E3ONwluPmfmVvzKKak71Ks16o8qzdpLD/iCL0yp4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057826; c=relaxed/simple; bh=Uj6RcsObzn8b/+SoVgCkDGSt0deGuP2kNzSx87R20Dg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=LFBSXf3Qf2gGqUFqVutuMyJ7GJG3qVwwrtK60bPiys9aJ4Qj/SZKoNEnfvWo/vvfdAc2RcBkR82ZFiaOKu3r4KOuB5ni6WvV37gzcCbrzmwt+fBVu1wnXGK/p+6nt6nGChTWfB4EWrCXVUp9hEMNvYPCpvvJRsfOvM6P7OcOQAs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fY84dwfz9v7NX; Wed, 11 Sep 2024 20:10:52 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 7E6301408D0; Wed, 11 Sep 2024 20:30:15 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S9; Wed, 11 Sep 2024 13:30:15 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 07/14] KEYS: Provide PGP key description autogeneration Date: Wed, 11 Sep 2024 14:29:04 +0200 Message-Id: <20240911122911.1381864-8-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S9 X-Coremail-Antispam: 1UD129KBjvJXoWxGFWfCF4fKF4rKFy7tw1fJFb_yoW5Zry3pa 15G3y5KFWrGr1fta9xGr4xG3sYyFWxJFWfK3ySvw1a9wsxXr10krWSyF1Yg3WayFn5JryS yFWqva4Ykr1DArDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPvb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVWxJVW8Jr1l84ACjcxK6I8E87Iv67AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr1j6F4UJwAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I 80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCj c4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4IIrI8v6xkF7I0E8cxan2IY04v7MxkF7I0En4 kS14v26r1q6r43MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E 5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtV W8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY 1x0267AKxVWxJVW8Jr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14 v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr1j6F4UJbIYCTnIWIevJa73UjIFyTuY vjxUF9NVUUUUU X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQHzQAHsF From: David Howells Provide a facility to autogenerate the name of PGP keys from the contents of the payload. If add_key() is given a blank description, a description is constructed from the last user ID packet in the payload data plus the last 8 hex digits of the key ID. For instance: keyctl padd asymmetric "" @s Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/pgp_public_key.c | 47 ++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/crypto/asymmetric_keys/pgp_public_key.c b/crypto/asymmetric_keys/pgp_public_key.c index 94284a78bf9b..22f4a40c7eb7 100644 --- a/crypto/asymmetric_keys/pgp_public_key.c +++ b/crypto/asymmetric_keys/pgp_public_key.c @@ -54,6 +54,8 @@ struct pgp_key_data_parse_context { struct public_key *pub; u8 raw_fingerprint[HASH_MAX_DIGESTSIZE]; size_t raw_fingerprint_len; + const char *user_id; + size_t user_id_len; }; /* @@ -200,6 +202,15 @@ static int pgp_process_public_key(struct pgp_parse_context *context, kenter(",%u,%u,,%zu", type, headerlen, datalen); + if (type == PGP_PKT_USER_ID) { + if (!ctx->user_id_len) { + ctx->user_id = data; + ctx->user_id_len = datalen; + } + kleave(" = 0 [user ID]"); + return 0; + } + if (ctx->raw_fingerprint_len) { kleave(" = -ENOKEY [already]"); return -EBADMSG; @@ -307,7 +318,8 @@ static int pgp_key_parse(struct key_preparsed_payload *prep) kenter(""); memset(&ctx, 0, sizeof(ctx)); - ctx.pgp.types_of_interest = (1 << PGP_PKT_PUBLIC_KEY); + ctx.pgp.types_of_interest = (1 << PGP_PKT_PUBLIC_KEY) | + (1 << PGP_PKT_USER_ID); ctx.pgp.process_packet = pgp_process_public_key; ret = pgp_parse_packets(prep->data, prep->datalen, &ctx.pgp); @@ -320,6 +332,39 @@ static int pgp_key_parse(struct key_preparsed_payload *prep) goto error; } + if (ctx.user_id && ctx.user_id_len > 0) { + /* + * Propose a description for the key (user ID without the + * comment). + */ + size_t ulen = ctx.user_id_len; + const char *p; + + p = memchr(ctx.user_id, '(', ulen); + if (p) { + /* Remove the comment */ + do { + p--; + } while (*p == ' ' && p > ctx.user_id); + if (*p != ' ') + p++; + ulen = p - ctx.user_id; + } + + if (ulen > 255 - 9) + ulen = 255 - 9; + prep->description = kmalloc(ulen + 1 + 8 + 1, GFP_KERNEL); + ret = -ENOMEM; + if (!prep->description) + goto error; + memcpy(prep->description, ctx.user_id, ulen); + prep->description[ulen] = ' '; + bin2hex(prep->description + ulen + 1, + ctx.raw_fingerprint + ctx.raw_fingerprint_len - 4, 4); + prep->description[ulen + 9] = 0; + pr_debug("desc '%s'\n", prep->description); + } + /* We're pinning the module by being linked against it */ __module_get(public_key_subtype.owner); prep->payload.data[asym_subtype] = &public_key_subtype; From patchwork Wed Sep 11 12:29:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800391 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 37D3E770E8; Wed, 11 Sep 2024 12:30:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057826; cv=none; b=Hba52oydVMOBVdxJj1ejLfS1DvEQ4JLO3bNVWoi6JgGG1L86TihkYisKKtFzfs2zskWfpPCjRT1/ezhaT42Kigz5qTe+0vXvROTHc1UjnbhpD2I1WmLGMy+iDjRjDLRSHF9jFE9+HwwnYQcgqpfW8oVy073VDImnvzm0tSVofK0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057826; c=relaxed/simple; bh=L8v4gYD4TS78WG8lZ5jWmDtPzUNPS8ZI6JzC9o5U/Zk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gfGqeZIX7zWEWQrc4LtLui026g65JxmvtzcnfpuHb7LhhKHEVZxUt00ZrBOUeAmMX2F+dt1uD67LP6qGDZI0lWJJ0ENvwmSfGGHcqARjOnq/tHmFR2qEvrxGGkvjF7VHCdDFkYMMGBCKVBljSLRoXeTYpvspRriM0o/uZE+/q9U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fYB2qnMz9v7NN; Wed, 11 Sep 2024 20:10:54 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 64527140452; Wed, 11 Sep 2024 20:30:21 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S10; Wed, 11 Sep 2024 13:30:20 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 08/14] KEYS: PGP-based public key signature verification Date: Wed, 11 Sep 2024 14:29:05 +0200 Message-Id: <20240911122911.1381864-9-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S10 X-Coremail-Antispam: 1UD129KBjvAXoW3Zw4fKFWkWry3CF4DJw4xWFg_yoW8WFy8Co WfW3y5Gw1Fqr1jkF43GFn7AF4qqF48W3WUArsYq34DW3WYv34UG3Wvkay3Gr4agF4fKryr Ar4Fqw13ZF4UKas5n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUOY7kC6x804xWl14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK 8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF 0E3s1l82xGYIkIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vE j48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_JFI_Gr1l84ACjcxK6xIIjxv20xvEc7CjxV AFwI0_Cr0_Gr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E 14v26r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrV C2j2WlYx0E2Ix0cI8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE 7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262 kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s02 6c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw 0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvE c7CjxVAFwI0_Cr0_Gr1UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67 AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v26r4UJVWxJrUvcSsGvfC2KfnxnUUI43ZE Xa7IU1aLvJUUUUU== X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgADBGbg-PsHuwAAs4 From: David Howells Provide handlers for PGP-based public-key algorithm signature verification. This does most of the work involved in signature verification as most of it is public-key algorithm agnostic. The public-key verification algorithm itself is just the last little bit and is supplied the complete hash data to process. This requires glue logic putting on top to make use of it - something that the patch introducing verify_pgp_signature() provides. Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- MAINTAINERS | 1 + crypto/asymmetric_keys/Makefile | 3 +- crypto/asymmetric_keys/pgp_signature.c | 510 +++++++++++++++++++++++++ include/crypto/pgp.h | 30 ++ 4 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 crypto/asymmetric_keys/pgp_signature.c create mode 100644 include/crypto/pgp.h diff --git a/MAINTAINERS b/MAINTAINERS index f328373463b0..c005b59cc795 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3401,6 +3401,7 @@ L: keyrings@vger.kernel.org S: Maintained F: Documentation/crypto/asymmetric-keys.rst F: crypto/asymmetric_keys/ +F: include/crypto/pgp.h F: include/crypto/pkcs7.h F: include/crypto/public_key.h F: include/linux/verification.h diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index d197e8b23b83..e7ff01997eb2 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -87,4 +87,5 @@ obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o obj-$(CONFIG_PGP_KEY_PARSER) += pgp_key_parser.o pgp_key_parser-y := \ - pgp_public_key.o + pgp_public_key.o \ + pgp_signature.o diff --git a/crypto/asymmetric_keys/pgp_signature.c b/crypto/asymmetric_keys/pgp_signature.c new file mode 100644 index 000000000000..4b8df79f2968 --- /dev/null +++ b/crypto/asymmetric_keys/pgp_signature.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* PGP public key signature verification [RFC 9580] + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#define pr_fmt(fmt) "PGPSIG: "fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pgp_parser.h" + +struct pgp_current_pkt { + enum pgp_packet_tag type; + u8 headerlen; + const u8 *data; + size_t datalen; +}; + +struct pgp_sig_verify { + enum pgp_signature_version sig_version : 8; + enum pgp_signature_type sig_type; + struct public_key_signature *sig; + u8 signed_hash_msw[2]; + struct shash_desc *hash; + struct pgp_current_pkt pkt; +}; + +/* + * Find a key in the given keyring by issuer and authority. + */ +static struct key *pgp_request_asymmetric_key(struct pgp_sig_verify *ctx, + struct key *keyring) +{ + struct key *key; + __be32 *issuer32; + char id[20]; + + issuer32 = (__be32 *)ctx->sig->auth_ids[0]->data; + snprintf(id, sizeof(id), "id:%08x%08x", be32_to_cpu(issuer32[0]), + be32_to_cpu(issuer32[1])); + + kenter(",,%s", id); + + pr_debug("Look up public key: \"%s\"\n", id + 3); + + key = find_asymmetric_key(keyring, ctx->sig->auth_ids[0], + ctx->sig->auth_ids[1], NULL, true); + if (IS_ERR(key)) { + pr_debug("Request for public key \"%s\" err %ld\n", id + 3, + PTR_ERR(key)); + + switch (PTR_ERR(key)) { + /* Hide some search errors */ + case -EACCES: + case -ENOTDIR: + case -EAGAIN: + kleave(" = -ENOKEY"); + return ERR_PTR(-ENOKEY); + default: + kleave(" = %ld", PTR_ERR(key)); + return ERR_CAST(key); + } + } + + kleave(" = 0 [%x]", key_serial(key)); + return key; +} + +struct pgp_sig_parse_context { + struct pgp_parse_context pgp; + struct pgp_sig_parameters params; + struct pgp_current_pkt pkt; +}; + +static int pgp_parse_signature(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen) +{ + struct pgp_sig_parse_context *ctx = + container_of(context, struct pgp_sig_parse_context, pgp); + struct pgp_sig_parameters tmp_params; + struct pgp_current_pkt tmp_pkt = { type, headerlen, data, datalen}; + int ret; + + ret = pgp_parse_sig_params(&data, &datalen, &tmp_params); + if (ret < 0) + return ret; + + if (tmp_params.signature_type != PGP_SIG_BINARY_DOCUMENT_SIG && + tmp_params.signature_type != PGP_SIG_STANDALONE_SIG && + tmp_params.signature_type != PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY && + tmp_params.signature_type != PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY) + return 0; + + memcpy(&ctx->params, &tmp_params, sizeof(tmp_params)); + memcpy(&ctx->pkt, &tmp_pkt, sizeof(tmp_pkt)); + return 0; +} + +/** + * pgp_sig_parse - Begin the process of verifying a signature + * @sigdata: Signature blob + * @siglen: Length of signature blob + * + * This involves allocating the hash into which first the data and then the + * metadata will be put, and parsing the signature to get the issuer ID from + * which the key used to verify the signature will be searched. + * + * Return: A PGP sig context pointer on success, an error pointer on error. + */ +struct pgp_sig_verify *pgp_sig_parse(const u8 *sigdata, size_t siglen) +{ + struct pgp_sig_parse_context p; + struct pgp_sig_verify *ctx; + struct crypto_shash *tfm; + const char *pkey_algo; + size_t digest_size, desc_size; + int ret; + + kenter(",,%zu", siglen); + + p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); + p.pgp.process_packet = pgp_parse_signature; + p.pkt.data = NULL; + ret = pgp_parse_packets(sigdata, siglen, &p.pgp); + if (ret < 0) { + kleave(" = ERR_PTR [bad pkt]"); + return ERR_PTR(ret); + } + + if (!p.pkt.data) { + kleave(" = ERR_PTR [no pkt]"); + return ERR_PTR(-ENOENT); + } + + /* Check the signature itself for usefulness */ + if (p.params.pubkey_algo >= PGP_PUBKEY__LAST) + goto unsupported_pkey_algo; + pkey_algo = pgp_to_public_key_algo[p.params.pubkey_algo]; + if (!pkey_algo) + goto unsupported_pkey_algo; + + if (p.params.hash_algo >= PGP_HASH__LAST || + !pgp_hash_algorithms[p.params.hash_algo]) { + pr_debug("Unsupported hash algorithm %u\n", + p.params.hash_algo); + kleave(" = -ENOPKG [unsupp hash algo]"); + return ERR_PTR(-ENOPKG); + } + + pr_debug("Signature generated with %s hash\n", + pgp_hash_algorithms[p.params.hash_algo]); + + /* + * Allocate the hashing algorithm we're going to need and find out how + * big the hash operational data will be. + */ + tfm = crypto_alloc_shash(pgp_hash_algorithms[p.params.hash_algo], 0, 0); + if (IS_ERR(tfm)) { + ret = (PTR_ERR(tfm) == -ENOENT ? -ENOPKG : PTR_ERR(tfm)); + kleave(" = %d", ret); + return ERR_PTR(ret); + } + + desc_size = crypto_shash_descsize(tfm); + digest_size = crypto_shash_digestsize(tfm); + + /* + * We allocate the hash operational data storage on the end of our + * context data. + */ + ctx = kzalloc(sizeof(*ctx) + sizeof(struct shash_desc) + desc_size, + GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto error_have_shash; + } + + ctx->sig = kzalloc(sizeof(*ctx->sig), GFP_KERNEL); + if (!ctx->sig) { + ret = -ENOMEM; + goto error_have_ctx; + } + + ctx->sig->auth_ids[0] = asymmetric_key_generate_id(p.params.issuer.id, + sizeof(p.params.issuer.id), "", 0); + if (IS_ERR(ctx->sig->auth_ids[0])) { + ret = -ENOMEM; + goto error_have_ctx_sig; + } + + ctx->sig->encoding = "pkcs1"; + ctx->sig->pkey_algo = pkey_algo; + ctx->sig->hash_algo = pgp_hash_algorithms[p.params.hash_algo]; + ctx->sig->digest_size = digest_size; + ctx->hash = (struct shash_desc *)((void *)ctx + + sizeof(*ctx)); + ctx->hash->tfm = tfm; + ctx->sig_version = p.params.version; + ctx->sig_type = p.params.signature_type; + + memcpy(&ctx->pkt, &p.pkt, sizeof(p.pkt)); + + ret = crypto_shash_init(ctx->hash); + if (ret < 0) + goto error_have_auth_ids; + + kleave(" = %p", ctx); + return ctx; + +error_have_auth_ids: + kfree(ctx->sig->auth_ids[0]); +error_have_ctx_sig: + kfree(ctx->sig); +error_have_ctx: + kfree(ctx); +error_have_shash: + crypto_free_shash(tfm); + kleave(" = %d", ret); + return ERR_PTR(ret); + +unsupported_pkey_algo: + pr_debug("Unsupported public key algorithm %u\n", + p.params.pubkey_algo); + kleave(" = -ENOPKG [unsupp pk algo]"); + return ERR_PTR(-ENOPKG); +} + +/* + * Load data into the hash + */ +int pgp_sig_add_data(struct pgp_sig_verify *ctx, const void *data, + size_t datalen) +{ + return crypto_shash_update(ctx->hash, data, datalen); +} + +/* + * Extract required metadata from the signature packet and add what we need to + * the hash; finalise the hash. + */ +static int pgp_digest_signature(struct pgp_sig_verify *ctx) +{ + enum pgp_signature_version version; + unsigned int nbytes, nbytes_alloc; + enum pgp_packet_tag type = ctx->pkt.type; + const u8 *data = ctx->pkt.data; + size_t datalen = ctx->pkt.datalen; + int ret; + + kenter(",%u,,%zu", type, datalen); + + if (ctx->sig->digest) { + kleave(" = 0 [digest found]"); + return 0; + } + + version = *data; + if (version == PGP_SIG_VERSION_3) { + /* We just include an excerpt of the metadata from a V3 + * signature. + */ + crypto_shash_update(ctx->hash, data + 2, 5); + data += sizeof(struct pgp_signature_v3_packet); + datalen -= sizeof(struct pgp_signature_v3_packet); + } else if (version == PGP_SIG_VERSION_4) { + /* + * We add the whole metadata header and some of the hashed data + * for a V4 signature, plus a trailer. + */ + size_t hashedsz, unhashedsz; + u8 trailer[6]; + + hashedsz = 4 + 2 + (data[4] << 8) + data[5]; + crypto_shash_update(ctx->hash, data, hashedsz); + + trailer[0] = version; + trailer[1] = 0xffU; + trailer[2] = hashedsz >> 24; + trailer[3] = hashedsz >> 16; + trailer[4] = hashedsz >> 8; + trailer[5] = hashedsz; + + crypto_shash_update(ctx->hash, trailer, 6); + data += hashedsz; + datalen -= hashedsz; + + unhashedsz = 2 + (data[0] << 8) + data[1]; + data += unhashedsz; + datalen -= unhashedsz; + } + + if (datalen <= 2) { + kleave(" = -EBADMSG"); + return -EBADMSG; + } + + /* There's a quick check on the hash available. */ + ctx->signed_hash_msw[0] = *data++; + ctx->signed_hash_msw[1] = *data++; + datalen -= 2; + + /* + * And then the cryptographic data, which we'll need for the + * algorithm. + */ + ret = mpi_key_length(data, datalen, NULL, &nbytes); + if (ret < 0) { + kleave(" = -EBADMSG [key length]"); + return ret; + } + + if (datalen != nbytes + 2) { + kleave(" = -EBADMSG [size mismatch]"); + return -EBADMSG; + } + + nbytes_alloc = DIV_ROUND_UP(nbytes, 8) * 8; + + ctx->sig->s = kzalloc(nbytes_alloc, GFP_KERNEL); + if (!ctx->sig->s) { + ret = -ENOMEM; + goto out; + } + + memcpy(ctx->sig->s + nbytes_alloc - nbytes, data + 2, nbytes); + ctx->sig->s_size = nbytes_alloc; + + ctx->sig->digest = kmalloc(ctx->sig->digest_size, GFP_KERNEL); + if (!ctx->sig->digest) { + ret = -ENOMEM; + goto out; + } + + ret = crypto_shash_final(ctx->hash, ctx->sig->digest); + if (ret < 0) + goto out; + + pr_debug("hash: %*phN\n", ctx->sig->digest_size, ctx->sig->digest); +out: + kleave(" = %d", ret); + return ret; +} + +/** + * pgp_sig_get_digest - Finalize digest calculation + * @ctx: PGP sig verification context to use + * @buf: Buffer digest is written to + * @len: Buffer length + * @hash_algo: Digest algorithm + * + * Copy the calculated digest pointer, length and algorithm to the destinations + * provided by the caller. + * + * Return: 0 on success, a negative value on error. + */ +int pgp_sig_get_digest(struct pgp_sig_verify *ctx, const u8 **buf, u32 *len, + enum hash_algo *hash_algo) +{ + int ret, i; + + kenter(""); + + ret = pgp_digest_signature(ctx); + if (ret < 0) + goto out; + + i = match_string(hash_algo_name, HASH_ALGO__LAST, + ctx->sig->hash_algo); + if (i < 0) { + ret = -ENOENT; + goto out; + } + + *hash_algo = i; + *buf = ctx->sig->digest; + *len = ctx->sig->digest_size; +out: + kleave(" = %d", ret); + return ret; +} + +/** + * pgp_sig_verify - Verify the PGP signature + * @ctx: PGP sig verification context to use + * @keyring: Keyring containing the key for signature verification + * + * Search the key to be used for signature verification, and verify the PGP + * signature. + * + * Return: 0 if the signature is valid, a negative value otherwise. + */ +int pgp_sig_verify(struct pgp_sig_verify *ctx, struct key *keyring) +{ + const struct public_key *pub; + struct key *key; + int ret; + + kenter(""); + + ret = pgp_digest_signature(ctx); + if (ret < 0) + goto out; + + if (ctx->sig->digest[0] != ctx->signed_hash_msw[0] || + ctx->sig->digest[1] != ctx->signed_hash_msw[1]) { + pr_err("Hash (%02x%02x) mismatch against quick check (%02x%02x)\n", + ctx->sig->digest[0], ctx->sig->digest[1], + ctx->signed_hash_msw[0], ctx->signed_hash_msw[1]); + ret = -EKEYREJECTED; + goto out; + } + + /* Now we need to find a key to use */ + key = pgp_request_asymmetric_key(ctx, keyring); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto out; + } + + pub = key->payload.data[asym_crypto]; + + if (strcmp(ctx->sig->pkey_algo, pub->pkey_algo)) { + ret = -EKEYREJECTED; + goto out_key; + } + + ret = verify_signature(key, ctx->sig); +out_key: + key_put(key); +out: + kleave(" = %d", ret); + return ret; +} + +/** + * pgp_sig_verify_cancel - End the PGP signature verification + * @ctx: PGP sig verification context to use + * @keep_sig: Don't deallocate the signature + * + * Free the memory used for the signature verification. Keep only the signature, + * if requested. + */ +void pgp_sig_verify_cancel(struct pgp_sig_verify *ctx, bool keep_sig) +{ + kenter(""); + + crypto_free_shash(ctx->hash->tfm); + if (!keep_sig) + public_key_signature_free(ctx->sig); + + kfree(ctx); + + kleave(""); +} + +/** + * pgp_sig_get_sig - Return the PGP signature + * @ctx: PGP sig verification context to use + * @is_key_sig: Whether it is a public key signature + * + * Finalize the signature by calculating the digest if not already done. Then, + * return the PGP signature to the caller. + * + * Return: The PGP signature if successfully finalized, an error pointer + * otherwise. + */ +struct public_key_signature *pgp_sig_get_sig(struct pgp_sig_verify *ctx, + bool is_key_sig) +{ + int ret; + + if (is_key_sig && + ctx->sig_type != PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY && + ctx->sig_type != PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY) + return ERR_PTR(-EINVAL); + + ret = pgp_digest_signature(ctx); + if (ret < 0) + return ERR_PTR(-ENOENT); + + return ctx->sig; +} + +/** + * pgp_sig_get_version - Return the PGP signature version + * @ctx: PGP sig verification context to use + * + * Return the version of the PGP signature to the caller. + * + * Return: The PGP signature version. + */ +u8 pgp_sig_get_version(struct pgp_sig_verify *ctx) +{ + return ctx->sig_version; +} diff --git a/include/crypto/pgp.h b/include/crypto/pgp.h new file mode 100644 index 000000000000..99dd1ab6c1b1 --- /dev/null +++ b/include/crypto/pgp.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* PGP signature processing + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifndef _CRYPTO_PGP_H +#define _CRYPTO_PGP_H + +#include + +struct key; +struct pgp_sig_verify; + +/* + * pgp_signature.c + */ +extern struct pgp_sig_verify *pgp_sig_parse(const u8 *sigdata, size_t siglen); +extern int pgp_sig_add_data(struct pgp_sig_verify *ctx, + const void *data, size_t datalen); +extern int pgp_sig_get_digest(struct pgp_sig_verify *ctx, const u8 **buf, + u32 *len, enum hash_algo *hash_algo); +extern int pgp_sig_verify(struct pgp_sig_verify *ctx, struct key *keyring); +extern void pgp_sig_verify_cancel(struct pgp_sig_verify *ctx, bool keep_sig); +extern struct public_key_signature *pgp_sig_get_sig(struct pgp_sig_verify *ctx, + bool is_key_sig); +extern u8 pgp_sig_get_version(struct pgp_sig_verify *ctx); + +#endif /* _CRYPTO_PGP_H */ From patchwork Wed Sep 11 12:29:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800392 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout11.his.huawei.com (frasgout11.his.huawei.com [14.137.139.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1EE6D191F82; Wed, 11 Sep 2024 12:30:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057840; cv=none; b=rfCvPZgit64gBgFe4vmsjZPCUbLxZyTH5ejVuuYoRMKJQBuh8oz+VWpZuD0Sf+ebx6iUw48lWriHba9j2veShinfqILWUArWrTG3CpMGmeSKPnDFUvVFnHdXiGpZkjm+4d+9OgSKITA5hvs+qol4veRY8rUaqYxn2hE1omk47po= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057840; c=relaxed/simple; bh=QSWW0uOl6XHXEqmztTA7fQh5BzSULZPfrrSVF/tNx+8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=UdK+XjpgWK58sfAz5zqExczWidFoa/V6mLSkpWpfM2tIue+4uyv4OLv5ISVz9WwI22al5ZtuoS2b8OKs6ZACzb24Qxmz2NG+9dgaHuwre27uCN/fvxlR8xEztO7ujD47FegPrydODSg+3EaXInq9u+Yh7f7kO4IOe4URzzCBDOM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout11.his.huawei.com (SkyGuard) with ESMTP id 4X3fYQ5Yxzz9v7Hk; Wed, 11 Sep 2024 20:11:06 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.27]) by mail.maildlp.com (Postfix) with ESMTP id 5403814093A; Wed, 11 Sep 2024 20:30:27 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP2 (Coremail) with SMTP id GxC2BwD3pscjjeFmDBG3AA--.60453S11; Wed, 11 Sep 2024 13:30:26 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 09/14] KEYS: Retry asym key search with partial ID in restrict_link_by_signature() Date: Wed, 11 Sep 2024 14:29:06 +0200 Message-Id: <20240911122911.1381864-10-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: GxC2BwD3pscjjeFmDBG3AA--.60453S11 X-Coremail-Antispam: 1UD129KBjvJXoW7tF13Xr4kZryxWF1xWFyfJFb_yoW8GrW5pa y8CryFgry8K347Cay5Aw47W3yfCFs5Ar1fGrs3GwnxC3s0qFs8trWIvF47ury5Cr4IvryS vrWjgr1Ykw4UAF7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPlb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E 14v26r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrV C2j2WlYx0E2Ix0cI8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE 7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262 kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s02 6c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw 0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvE c7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aV AFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZF pf9x07UZTmfUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgADBGbg-PsHuwABs5 From: Roberto Sassu Retry asymmetric key search in restrict_link_by_signature() to support the case of partial IDs, provided by PGP signatures (only the last 8 bytes). Although RFC 9580 supports the signature subpacket type 33, which contains the full issuer fingerprint, we cannot rely on existing signatures to support it. Signed-off-by: Roberto Sassu Signed-off-by: David Howells --- crypto/asymmetric_keys/restrict.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index afcd4d101ac5..dd3d4b3405f7 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -97,8 +97,14 @@ int restrict_link_by_signature(struct key *dest_keyring, key = find_asymmetric_key(trust_keyring, sig->auth_ids[0], sig->auth_ids[1], sig->auth_ids[2], false); - if (IS_ERR(key)) - return -ENOKEY; + if (IS_ERR(key)) { + /* Retry with a partial ID. */ + key = find_asymmetric_key(trust_keyring, + sig->auth_ids[0], sig->auth_ids[1], + sig->auth_ids[2], true); + if (IS_ERR(key)) + return -ENOKEY; + } if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags)) ret = -ENOKEY; From patchwork Wed Sep 11 12:29:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800442 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6FDC6190675; Wed, 11 Sep 2024 12:31:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057915; cv=none; b=X832yxv8x59BgC4mrL/FeS2V2j1BdiHoayZjggpjJVZLvJOgv/LiYKsaJwFx9t/c+shFWranNt/ojeZcxvtse2BZ6BbHJikmclFaKrZ1GYgHDKwo4hpEcc/hzixeAIQHKTKNcaQgmtXeW0ld8wn8XLjezExfBIZQl1pUNk17rwo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057915; c=relaxed/simple; bh=fKPBAd7EgzmecWQuOmZuawdzDkVqpzhqT1bVYZNDujw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=boxRD/qMzv+uqNUH4OwrsQ/0t/PlZsV8VQZ4vE5p1SEEAV9J2iG3Drq23anUWZk5FqQzi5rLww3IJnl4CEq8k5R7az70YcDZHNQxBM8JPTVgyoGJGdzKpzdXL4i3esskceiIsjqao/G/fgBS33DkrLW90NFJawLx/QCv+JAKFLM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fZv4jMnz9v7NF; Wed, 11 Sep 2024 20:12:23 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id A8426140B03; Wed, 11 Sep 2024 20:31:37 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwD3hy+ijeFmnHu1AA--.60036S2; Wed, 11 Sep 2024 13:31:37 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 10/14] KEYS: Calculate key digest and get signature of the key Date: Wed, 11 Sep 2024 14:29:07 +0200 Message-Id: <20240911122911.1381864-11-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwD3hy+ijeFmnHu1AA--.60036S2 X-Coremail-Antispam: 1UD129KBjvJXoWxXrW7Zw1DGr1UWry7CFW7urg_yoWrZr43pF WrKryftrW5Krn2ka98Jw4xu3yF9348Cw1fK34Skw1a93sYqr1UCay09F1jgF98GFykAryr AFWqyFWa9r1DZrDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUvvb4IE77IF4wAFF20E14v26r4j6ryUM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4 vEj48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7Cj xVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26r4j6F4UM28EF7xvwVC2z280aVCY1x 0267AKxVW8Jr0_Cr1UM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02 F40Ex7xfMcIj6xIIjxv20xvE14v26r106r15McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4I kC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lFIxGxcIEc7CjxVA2Y2ka0xkIwI1lc7Cj xVAaw2AFwI0_Jw0_GFyl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2 IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v2 6r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Gr0_Xr1lIxAIcVC0I7IYx2 IY6xkF7I0E14v26r4UJVWxJr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2 jsIE14v26r4j6F4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr1j6F4UJbIYCTnIWIevJa73Uj IFyTuYvjxUOBMKDUUUU X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQH4wAAss From: Roberto Sassu Calculate the digest of the signature, according to the RFC 9580 section 5.2.4, get the last suitable signature with types 0x10 (Generic certification of a User ID and Public-Key packet) or 0x13 (Positive certification of a User ID and Public Key packet), and store it in the asym_auth field of the key payload, so that it is available for validating a restriction on a keyring. Type 0x10 is included despite not giving the strongest trust guarantees, since it is the one used by most common PGP implementations (including gpg). The rationale of taking the last signature is that, if there are multiple signatures, that would be of a different issuer (not a self-signature), that likely has more chances to be useful for the restriction verification. If there is one (the self-signature), that will be used. Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/pgp_public_key.c | 81 +++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/crypto/asymmetric_keys/pgp_public_key.c b/crypto/asymmetric_keys/pgp_public_key.c index 22f4a40c7eb7..2dc8b5d321e9 100644 --- a/crypto/asymmetric_keys/pgp_public_key.c +++ b/crypto/asymmetric_keys/pgp_public_key.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "pgp_parser.h" @@ -56,6 +57,8 @@ struct pgp_key_data_parse_context { size_t raw_fingerprint_len; const char *user_id; size_t user_id_len; + const char *key_pkt; + size_t key_pkt_len; }; /* @@ -216,6 +219,12 @@ static int pgp_process_public_key(struct pgp_parse_context *context, return -EBADMSG; } + /* Pointer refers to data being processed. */ + if (type == PGP_PKT_PUBLIC_KEY) { + ctx->key_pkt = data; + ctx->key_pkt_len = datalen; + } + pub = kzalloc(sizeof(*pub), GFP_KERNEL); if (!pub) return -ENOMEM; @@ -306,6 +315,77 @@ pgp_key_generate_id(struct pgp_key_data_parse_context *ctx) return NULL; } +/* + * Calculate the digest of the signature according to the RFC 9580, section + * 5.2.4 (packet types 0x10 and 0x13). + */ +static int pgp_key_add_sig_data(struct pgp_key_data_parse_context *ctx, + struct pgp_sig_verify *sig_ctx) +{ + loff_t offset = 0; + u8 *data; + + if (!ctx->key_pkt_len || !ctx->user_id_len) + return 0; + + /* 0x99 + key pkt len + key pkt + 0xb4 + user ID len + user ID */ + data = kmalloc(1 + sizeof(u16) + ctx->key_pkt_len + + 1 + sizeof(u32) + ctx->user_id_len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data[offset++] = 0x99; + data[offset++] = ctx->key_pkt_len >> 8; + data[offset++] = ctx->key_pkt_len; + + memcpy(data + offset, ctx->key_pkt, ctx->key_pkt_len); + offset += ctx->key_pkt_len; + + if (pgp_sig_get_version(sig_ctx) == PGP_SIG_VERSION_4) { + data[offset++] = 0xb4; + data[offset++] = ctx->user_id_len >> 24; + data[offset++] = ctx->user_id_len >> 16; + data[offset++] = ctx->user_id_len >> 8; + data[offset++] = ctx->user_id_len; + } + + memcpy(data + offset, ctx->user_id, ctx->user_id_len); + offset += ctx->user_id_len; + + pgp_sig_add_data(sig_ctx, data, offset); + kfree(data); + return 0; +} + +static struct public_key_signature * +pgp_key_get_sig(struct key_preparsed_payload *prep, + struct pgp_key_data_parse_context *ctx) +{ + struct public_key_signature *sig = NULL; + struct pgp_sig_verify *sig_ctx; + bool keep_sig = false; + int ret; + + sig_ctx = pgp_sig_parse(prep->data, prep->datalen); + if (IS_ERR(sig_ctx)) + return NULL; + + ret = pgp_key_add_sig_data(ctx, sig_ctx); + if (ret < 0) + goto out; + + sig = pgp_sig_get_sig(sig_ctx, true); + if (IS_ERR(sig)) { + sig = NULL; + goto out; + } + + keep_sig = true; +out: + pgp_sig_verify_cancel(sig_ctx, keep_sig); + return sig; +} + /* * Attempt to parse the instantiation data blob for a key as a PGP packet * message holding a key. @@ -370,6 +450,7 @@ static int pgp_key_parse(struct key_preparsed_payload *prep) prep->payload.data[asym_subtype] = &public_key_subtype; prep->payload.data[asym_key_ids] = pgp_key_generate_id(&ctx); prep->payload.data[asym_crypto] = ctx.pub; + prep->payload.data[asym_auth] = pgp_key_get_sig(prep, &ctx); prep->quotalen = 100; return 0; From patchwork Wed Sep 11 12:29:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800443 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout12.his.huawei.com (frasgout12.his.huawei.com [14.137.139.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B802F188A14; Wed, 11 Sep 2024 12:31:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057915; cv=none; b=RyY2XN4Aj4h0s/3+Pp/Dm0yZVatW5ctmlGvndSYOY+/K6SIJIfrDmdGtLwPwlufbVpBX/WZ2EGhyfJX/qrbXlGXZUUOf6U8AC+6yyzZs78artwujsz8AbWsxIr0ikCcwMLjo0CaSpQ1gQVihqF8uuzlhtAeLZrXlfow/EXrAQ9U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057915; c=relaxed/simple; bh=2KIlpazax1UQiWf3Y3CqCE/n7smW3FLZV6HkbuAAgcQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TE4HR7CBmO2i2I5KURn4LZxMwf59uY2juWr2dJvspKl1k9/ZzgWBibTGsx/OMQ/CqxgRTxS4d0gdXyswzy8742PAhsN+g5mZCDy6M1ihbM8gwrZT8jL+3Itm1ZxERL+N59T4wxT4xEmYRxWhagOCoEBwW27dtugrNozKCa2HIyc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout12.his.huawei.com (SkyGuard) with ESMTP id 4X3fSH1TtHz9v7JT; Wed, 11 Sep 2024 20:06:39 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id 762B8140B08; Wed, 11 Sep 2024 20:31:43 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwD3hy+ijeFmnHu1AA--.60036S3; Wed, 11 Sep 2024 13:31:43 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 11/14] verification: introduce verify_pgp_signature() Date: Wed, 11 Sep 2024 14:29:08 +0200 Message-Id: <20240911122911.1381864-12-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwD3hy+ijeFmnHu1AA--.60036S3 X-Coremail-Antispam: 1UD129KBjvJXoWxJF1kGF4kCF15JFyUJF4fZrb_yoWrCrWDpF nYvF4FvFy3Arn7Aay3Ga13Z3WrGrn5Kw17X3sFk3ZxXF97X3ZFyw4rKF4YqrW5C34UZrWF 9rZ2qFy3Cw1DJw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPqb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUGw A2048vs2IY020Ec7CjxVAFwI0_Gr0_Xr1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2 WlYx0E2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkE bVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7 AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02 F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GF ylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvEc7Cj xVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZFpf9x 07jb9NsUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgADBGbg-PsH0QAAsS From: Roberto Sassu Introduce verify_pgp_signature() to verify PGP signatures from detached data. It can be used by kernel subsystems (e.g. IMA). Signed-off-by: Roberto Sassu --- certs/system_keyring.c | 71 ++++++++++++++++++++++++++++++++++++ include/linux/verification.h | 23 ++++++++++++ 2 files changed, 94 insertions(+) diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 9de610bf1f4b..f132773c6096 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -16,6 +16,7 @@ #include #include #include +#include static struct key *builtin_trusted_keys; #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING @@ -418,6 +419,76 @@ int verify_pkcs7_signature(const void *data, size_t len, } EXPORT_SYMBOL_GPL(verify_pkcs7_signature); +#ifdef CONFIG_PGP_KEY_PARSER +/** + * verify_pgp_signature - Verify a PGP-based signature on system data. + * @data: The data to be verified (must be provided). + * @len: Size of @data. + * @raw_pgp: The PGP message that is the signature. + * @pgp_len: The size of @raw_pgp. + * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only, + * (void *)1UL for all trusted keys, + (void *)2UL for platform keys). + * @usage: The use to which the key is being put. + * @view_content: Callback to gain access to content. + * @ctx: Context for callback. + */ +int verify_pgp_signature(const void *data, size_t len, + const void *raw_pgp, size_t pgp_len, + struct key *trusted_keys, + enum key_being_used_for usage, + int (*view_content)(void *ctx, + const void *data, size_t len, + size_t asn1hdrlen), + void *ctx) +{ + struct pgp_sig_verify *pgp_ctx; + int ret; + + if (!data || !len) + return -EINVAL; + + pgp_ctx = pgp_sig_parse(raw_pgp, pgp_len); + if (IS_ERR(pgp_ctx)) + return PTR_ERR(pgp_ctx); + + if (!trusted_keys) { + trusted_keys = builtin_trusted_keys; + } else if (trusted_keys == VERIFY_USE_SECONDARY_KEYRING) { +#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING + trusted_keys = secondary_trusted_keys; +#else + trusted_keys = builtin_trusted_keys; +#endif + } else if (trusted_keys == VERIFY_USE_PLATFORM_KEYRING) { +#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING + trusted_keys = platform_trusted_keys; +#else + trusted_keys = NULL; +#endif + if (!trusted_keys) { + ret = -ENOKEY; + pr_devel("PGP platform keyring is not available\n"); + goto error; + } + } + + /* The data should be detached - so we need to supply it. */ + if (pgp_sig_add_data(pgp_ctx, data, len)) { + pr_err("Failed to supply data for PGP signature\n"); + ret = -EBADMSG; + goto error; + } + + ret = pgp_sig_verify(pgp_ctx, trusted_keys); +error: + pgp_sig_verify_cancel(pgp_ctx, false); + pr_devel("<==%s() = %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL_GPL(verify_pgp_signature); + +#endif /* CONFIG_PGP_KEY_PARSER */ #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ #ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING diff --git a/include/linux/verification.h b/include/linux/verification.h index cb2d47f28091..e1a3b9424b67 100644 --- a/include/linux/verification.h +++ b/include/linux/verification.h @@ -63,6 +63,29 @@ extern int verify_pkcs7_message_sig(const void *data, size_t len, size_t asn1hdrlen), void *ctx); +#ifdef CONFIG_PGP_KEY_PARSER +extern int verify_pgp_signature(const void *data, size_t len, + const void *raw_pgp, size_t pgp_len, + struct key *trusted_keys, + enum key_being_used_for usage, + int (*view_content)(void *ctx, + const void *data, size_t len, + size_t asn1hdrlen), + void *ctx); +#else +static inline int verify_pgp_signature(const void *data, size_t len, + const void *raw_pgp, size_t pgp_len, + struct key *trusted_keys, + enum key_being_used_for usage, + int (*view_content)(void *ctx, + const void *data, size_t len, + size_t asn1hdrlen), + void *ctx) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_PGP_KEY_PARSER */ + #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION extern int verify_pefile_signature(const void *pebuf, unsigned pelen, struct key *trusted_keys, From patchwork Wed Sep 11 12:29:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800444 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1004B1A4E65; Wed, 11 Sep 2024 12:31:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057919; cv=none; b=et4ysBSWCTvfQReO9ggh6wfsCHmCee/WYlcUTqghdLEfEIO9GxwKJGhhlY2Dho7TBoa+efgWzPvQmDlePFk5EPXnuV6PJCUdsOcNoPELYVVyqHorEgcf6Z2TwUgmTcsuiidMA5iF1JPsXlpQQSodEGjiIQLzYA8RnH7Kp+wBjMI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057919; c=relaxed/simple; bh=5h+KprFeInb15D7Ak0CKlRDmGyk19qjtw15wRdc0M/g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=OODJDKRsk0WV0cACZDUCC8qOLESOpsXdhnUJdfrfYq08VgfTmYIGlzghmmyRdYz7wFJ/BWvONdrtgXK4NYZXwHFtpNMvfyD4EafyP8BP+7HSayi7f311Q5QoJqfx8GpreBHhspvRg0JmGLahVPc2O2jL+yfxh1BE0JfuN7TntYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fZz2ZFHz9v7NN; Wed, 11 Sep 2024 20:12:27 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id 55D88140580; Wed, 11 Sep 2024 20:31:49 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwD3hy+ijeFmnHu1AA--.60036S4; Wed, 11 Sep 2024 13:31:48 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 12/14] PGP: Provide a key type for testing PGP signatures Date: Wed, 11 Sep 2024 14:29:09 +0200 Message-Id: <20240911122911.1381864-13-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwD3hy+ijeFmnHu1AA--.60036S4 X-Coremail-Antispam: 1UD129KBjvJXoWxtrW5XrWkWr1xtFW8ZFyfXrb_yoWfXr43pF yFkrWrtFy8Jrn7C3y3AayfWwnYkr40yry3G3ySqw1jy39rWwn7GrZ2yF1kKF98tw4kZ3yr A3yYva4Uu3WDtrDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPqb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUXw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2 WlYx0E2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkE bVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7 AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02 F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GF ylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvEc7Cj xVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZFpf9x 07Ud5rcUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQH5AAAsr From: David Howells Provide a key type for testing the PGP signature parser. It is given a non-detached PGP message as payload: keyctl padd pgp_test a @s content.txt gpg --compress-algo=none -s content.txt Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/Kconfig | 15 +++ crypto/asymmetric_keys/Makefile | 2 + crypto/asymmetric_keys/pgp_library.c | 64 +++++++++++++ crypto/asymmetric_keys/pgp_test_key.c | 131 ++++++++++++++++++++++++++ crypto/asymmetric_keys/pgplib.h | 16 ++++ 5 files changed, 228 insertions(+) create mode 100644 crypto/asymmetric_keys/pgp_test_key.c diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index c69bfdc022c0..d28b9593a70d 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -119,4 +119,19 @@ config PGP_KEY_PARSER for key data and provides the ability to instantiate a crypto key from a public key packet found inside the blob. +config PGP_TEST_KEY + tristate "PGP testing key type" + depends on SYSTEM_DATA_VERIFICATION + depends on PGP_KEY_PARSER=y + help + This option provides a type of key that can be loaded up from a + PGP message - provided the message is signed by a loaded key. If + it is, the PGP wrapper is discarded and reading the key returns + just the payload. If it isn't, adding the key will fail with an + error. If the key used for signature verification isn't in the + built-in or secondary keyring, adding a key will succeed but this + fact will be signaled through a debug message in the kernel log. + + This is intended for testing the PGP parser. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e7ff01997eb2..507a78f9a0a1 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -89,3 +89,5 @@ obj-$(CONFIG_PGP_KEY_PARSER) += pgp_key_parser.o pgp_key_parser-y := \ pgp_public_key.o \ pgp_signature.o + +obj-$(CONFIG_PGP_TEST_KEY) += pgp_test_key.o diff --git a/crypto/asymmetric_keys/pgp_library.c b/crypto/asymmetric_keys/pgp_library.c index a9708ccbcb81..ff4bb52790dd 100644 --- a/crypto/asymmetric_keys/pgp_library.c +++ b/crypto/asymmetric_keys/pgp_library.c @@ -544,3 +544,67 @@ int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, return 0; } EXPORT_SYMBOL_GPL(pgp_parse_sig_params); + +#if IS_ENABLED(CONFIG_PGP_TEST_KEY) + +/** + * pgp_parse_literal_data - Parse basic params from a PGP literal data packet + * @data: Content of packet + * @datalen: Length of packet remaining + * @p: The basic parameters + * + * Parse the basic parameters from a PGP literal data packet [RFC 9580: 5.9] + * that are needed to work out what form the data is in and where it is. + * + * Returns 0 if successful or a negative error code. + */ +int pgp_parse_literal_data(const u8 *data, size_t datalen, + struct pgp_literal_data_parameters *p) +{ + unsigned int tmp; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 6) + goto too_short; + datalen -= 6; + + p->format = *data++; + switch (p->format) { + case PGP_LIT_FORMAT_BINARY: + case PGP_LIT_FORMAT_TEXT: + case PGP_LIT_FORMAT_TEXT_UTF8: + break; + default: + pr_debug("Literal data packet with unhandled format %02x\n", + p->format); + return -EBADMSG; + } + + p->filename_len = *data++; + p->filename_offset = 2; + if (datalen < p->filename_len) + goto too_short; + data += p->filename_len; + datalen -= p->filename_len; + + tmp = *data++ << 24; + tmp |= *data++ << 16; + tmp |= *data++ << 8; + tmp |= *data++; + p->time = tmp; + + p->content_offset = 6 + p->filename_len; + p->content_len = datalen; + + pr_devel("%x,%u,%x,%u\n", + p->format, p->filename_len, p->time, p->content_len); + return 0; + +too_short: + pr_debug("Literal data packet too short\n"); + return -EBADMSG; +} +EXPORT_SYMBOL_GPL(pgp_parse_literal_data); + +#endif /* CONFIG_PGP_TEST_KEY */ diff --git a/crypto/asymmetric_keys/pgp_test_key.c b/crypto/asymmetric_keys/pgp_test_key.c new file mode 100644 index 000000000000..80ab72ed09b9 --- /dev/null +++ b/crypto/asymmetric_keys/pgp_test_key.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Testing module to load key from trusted PGP message + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#define pr_fmt(fmt) "PGPtest: "fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pgp_parser.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PGP testing key type"); + +struct pgp_test_parse_context { + struct pgp_parse_context pgp; + struct pgp_literal_data_parameters params; + const void *content; +}; + +static int pgp_test_parse_data(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen) +{ + struct pgp_test_parse_context *ctx = + container_of(context, struct pgp_test_parse_context, pgp); + int ret; + + kenter(""); + + ret = pgp_parse_literal_data(data, datalen, &ctx->params); + if (ret == 0) + ctx->content = data + ctx->params.content_offset; + return ret; +} + +/* + * Instantiate a PGP wrapped and validated key. + */ +static int pgp_test_instantiate(struct key *key, + struct key_preparsed_payload *prep) +{ + struct pgp_test_parse_context p; + const void *saved_prep_data; + size_t saved_prep_datalen; + const struct cred *cred = current_cred(); + int ret; + + kenter(""); + + memset(&p, 0, sizeof(p)); + p.pgp.types_of_interest = (1 << PGP_PKT_LITERAL_DATA); + p.pgp.process_packet = pgp_test_parse_data; + ret = pgp_parse_packets(prep->data, prep->datalen, &p.pgp); + if (ret < 0) { + kleave(" = %d [parse]", ret); + return ret; + } + + if (!p.params.content_len) { + kleave(" = -ENODATA [no literal data"); + return -ENODATA; + } + + ret = verify_pgp_signature(p.content, p.params.content_len, + prep->data, prep->datalen, + VERIFY_USE_SECONDARY_KEYRING, + VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); + if (ret < 0 && cred->session_keyring) { + ret = verify_pgp_signature(p.content, p.params.content_len, + prep->data, prep->datalen, + cred->session_keyring, + VERIFYING_UNSPECIFIED_SIGNATURE, + NULL, NULL); + if (ret < 0) + goto error; + + pr_warn("PGP message doesn't chain back to a trusted key\n"); + } + + saved_prep_data = prep->data; + saved_prep_datalen = prep->datalen; + prep->data = p.content; + prep->datalen = p.params.content_len; + ret = generic_key_instantiate(key, prep); + prep->data = saved_prep_data; + prep->datalen = saved_prep_datalen; +error: + kleave(" = %d", ret); + return ret; +} + +/* + * user defined keys take an arbitrary string as the description and an + * arbitrary blob of data as the payload + */ +static struct key_type key_type_pgp_test = { + .name = "pgp_test", + .instantiate = pgp_test_instantiate, + .revoke = user_revoke, + .destroy = user_destroy, + .describe = user_describe, + .read = user_read, +}; + +/* + * Module stuff + */ +static int __init pgp_key_init(void) +{ + return register_key_type(&key_type_pgp_test); +} + +static void __exit pgp_key_cleanup(void) +{ + unregister_key_type(&key_type_pgp_test); +} + +module_init(pgp_key_init); +module_exit(pgp_key_cleanup); diff --git a/crypto/asymmetric_keys/pgplib.h b/crypto/asymmetric_keys/pgplib.h index 25191cea33a4..9c852256d1c9 100644 --- a/crypto/asymmetric_keys/pgplib.h +++ b/crypto/asymmetric_keys/pgplib.h @@ -56,3 +56,19 @@ struct pgp_sig_parameters { extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, struct pgp_sig_parameters *p); + +#if IS_ENABLED(CONFIG_PGP_TEST_KEY) + +struct pgp_literal_data_parameters { + enum pgp_literal_data_format format : 8; + u8 filename_len; + u8 filename_offset; + u8 content_offset; + u32 content_len; + u32 time; +}; + +extern int pgp_parse_literal_data(const u8 *data, size_t datalen, + struct pgp_literal_data_parameters *p); + +#endif /* CONFIG_PGP_TEST_KEY */ From patchwork Wed Sep 11 12:29:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800445 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout13.his.huawei.com (frasgout13.his.huawei.com [14.137.139.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7BCF1A4E92; Wed, 11 Sep 2024 12:31:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057919; cv=none; b=O14e1NWsmveAr/4ZCyetTAA0imTVqkfv3U4+J/ET0nOkppdn+S3eyaod9lziOIDz5vCeFMGFX5EBQHrUk996PhrhpHJvkCwz230QuI+7QqrPC+1KCpURwELTY4IAVBkcJvoNlrsx7rJW2jPZWiDh9MW8Qs8vwWzIYFVQFISLScs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057919; c=relaxed/simple; bh=3OdJJYzevKbKCSSdml7OTqQpyYXDzm+jDC5UwtxfIWg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fEOYc650LaA7MeumKGX363NARMfnj65SAOTzzqn2a8zctCmB7LMCYq0IpABcLN64Nz36PJ910ZqCeGccTRkhxdTfIoSqbB2+dEYBaEJL4hn/sIp4go2jeBz297+Z9RvUEmwxTmKtX4nBZ9vDyVzOQG9NJZQDhjrj93GcFlK2D3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.29]) by frasgout13.his.huawei.com (SkyGuard) with ESMTP id 4X3fb00RMyz9v7NT; Wed, 11 Sep 2024 20:12:28 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id 14F4F140413; Wed, 11 Sep 2024 20:31:55 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwD3hy+ijeFmnHu1AA--.60036S5; Wed, 11 Sep 2024 13:31:54 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 13/14] KEYS: Provide a function to load keys from a PGP keyring blob Date: Wed, 11 Sep 2024 14:29:10 +0200 Message-Id: <20240911122911.1381864-14-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwD3hy+ijeFmnHu1AA--.60036S5 X-Coremail-Antispam: 1UD129KBjvJXoW3Jw15KF18WF1rCr1xCF1Dtrb_yoWxXw1rpF W0kryrtFWkGr9Ik3yrAw1Ig34Fyr1vyFW5GrWSyw15Ar9rXa18KrZ29r4DKa47Ars7t34r trWq934YyF1DtrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPqb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUWw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2 WlYx0E2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkE bVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262kKe7 AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02 F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GF ylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvEc7Cj xVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI 0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZFpf9x 07UHnmiUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAgADBGbg-PsH0gAAsR From: David Howells Provide a function to load keys from a PGP keyring blob to the built-in and .ima keyrings: int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, struct key *keyring); Descriptions are generated from user ID notes and key fingerprints. The keys will actually be identified by the ID calculated from the PGP data rather than by the description, so this shouldn't be a problem. The keys are attached to the keyring supplied. Looking as root in /proc/keys after the built-in keyring has been loaded: 383a00c1 I------ 1 perm 1f030000 0 0 asymmetri \ Red Hat, Inc. dbeca166: PGP.DSA dbeca166 [] Thanks to Tetsuo Handa for some pointing out some errors. Signed-off-by: David Howells Co-developed-by: Roberto Sassu Signed-off-by: Roberto Sassu --- crypto/asymmetric_keys/Kconfig | 8 ++ crypto/asymmetric_keys/Makefile | 1 + crypto/asymmetric_keys/pgp_preload.c | 111 +++++++++++++++++++++++++++ include/crypto/pgp.h | 8 +- 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 crypto/asymmetric_keys/pgp_preload.c diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index d28b9593a70d..fc1a0d692a53 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -134,4 +134,12 @@ config PGP_TEST_KEY This is intended for testing the PGP parser. +config PGP_PRELOAD + bool "PGP public key preloading facility" + depends on SYSTEM_TRUSTED_KEYRING + select PGP_KEY_PARSER + help + This option provides a facility for the kernel to preload PGP-wrapped + bundles of keys during boot to the built-in and .ima keyrings. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 507a78f9a0a1..2fa55a7830e6 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -84,6 +84,7 @@ $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h # PGP handling # obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o +obj-$(CONFIG_PGP_PRELOAD) += pgp_preload.o obj-$(CONFIG_PGP_KEY_PARSER) += pgp_key_parser.o pgp_key_parser-y := \ diff --git a/crypto/asymmetric_keys/pgp_preload.c b/crypto/asymmetric_keys/pgp_preload.c new file mode 100644 index 000000000000..e0776dc8f928 --- /dev/null +++ b/crypto/asymmetric_keys/pgp_preload.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Asymmetric key request handling + * + * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include +#include +#include +#include +#include + +#include "pgp_parser.h" + +struct preload_pgp_keys_context { + struct pgp_parse_context pgp; + key_ref_t keyring; + const u8 *key_start; + const u8 *key_end; + bool found_key; +}; + +/* + * Create a key. + */ +static void __init create_pgp_key(struct preload_pgp_keys_context *ctx) +{ + key_ref_t key; + + key = key_create_or_update(ctx->keyring, + "asymmetric", + NULL, + ctx->key_start, + ctx->key_end - ctx->key_start, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ), + KEY_ALLOC_NOT_IN_QUOTA | + KEY_ALLOC_BUILT_IN | + KEY_ALLOC_BYPASS_RESTRICTION); + if (IS_ERR(key)) { + pr_notice("Ignoring PGP key, error: %ld\n", PTR_ERR(key)); + return; + } + + pr_notice("Loaded PGP key '%s'\n", + key_ref_to_ptr(key)->description); + + key_ref_put(key); +} + +/* + * Extract a public key or subkey from the PGP stream. + */ +static int __init found_pgp_key(struct pgp_parse_context *context, + enum pgp_packet_tag type, u8 headerlen, + const u8 *data, size_t datalen) +{ + struct preload_pgp_keys_context *ctx = + container_of(context, struct preload_pgp_keys_context, pgp); + + if (ctx->found_key) { + ctx->key_end = data - headerlen; + create_pgp_key(ctx); + } + + ctx->key_start = data - headerlen; + ctx->found_key = true; + return 0; +} + +/** + * preload_pgp_keys - Load keys from a PGP keyring blob + * @pgpdata: The PGP keyring blob containing the keys. + * @pgpdatalen: The size of the @pgpdata blob. + * @keyring: The keyring to add the new keys to. + * + * Preload a pack of keys from a PGP keyring blob. + * + * The keys have their descriptions generated from the user ID and fingerprint + * in the PGP stream. Since keys can be matched on their key IDs independently + * of the key description, the description is mostly irrelevant apart from the + * fact that keys of the same description displace one another from a keyring. + * + * The caller should override the current creds if they want the keys to be + * owned by someone other than the current process's owner. Keys will not be + * accounted towards the owner's quota. + * + * This function may only be called whilst the kernel is booting. + */ +int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, + struct key *keyring) +{ + struct preload_pgp_keys_context ctx; + int ret; + + ctx.pgp.types_of_interest = (1 << PGP_PKT_PUBLIC_KEY); + ctx.pgp.process_packet = found_pgp_key; + ctx.keyring = make_key_ref(keyring, 1); + ctx.found_key = false; + + ret = pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp); + if (ret < 0) + return ret; + + if (ctx.found_key) { + ctx.key_end = pgpdata + pgpdatalen; + create_pgp_key(&ctx); + } + return 0; +} diff --git a/include/crypto/pgp.h b/include/crypto/pgp.h index 99dd1ab6c1b1..263b44603636 100644 --- a/include/crypto/pgp.h +++ b/include/crypto/pgp.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -/* PGP signature processing +/* PGP key and signature processing * * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) @@ -27,4 +27,10 @@ extern struct public_key_signature *pgp_sig_get_sig(struct pgp_sig_verify *ctx, bool is_key_sig); extern u8 pgp_sig_get_version(struct pgp_sig_verify *ctx); +/* + * pgp_preload.c + */ +extern int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, + struct key *keyring); + #endif /* _CRYPTO_PGP_H */ From patchwork Wed Sep 11 12:29:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roberto Sassu X-Patchwork-Id: 13800446 X-Patchwork-Delegate: herbert@gondor.apana.org.au Received: from frasgout12.his.huawei.com (frasgout12.his.huawei.com [14.137.139.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E81718C03E; Wed, 11 Sep 2024 12:32:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=14.137.139.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057933; cv=none; b=WElKJtNebpz447xM1hRw97onHPw0rk1EU/F3MUqBf8hkVw8V8bXgBxAh+Abu2hYNxD7MqBNXUl+DnYjWSxLkmO5GdrKsEF/+D8gQRcDCImM5Uo7Y0ES31kmEUFBoSC53SDOrdFfx/w0j4+B14nATpHWdlNdd6nsw/vkAR7CxhsY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726057933; c=relaxed/simple; bh=tSytCnfi4nnQFFL8WhpSzw4/Y/VqtTFp8/HjS3cG67E=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JW9yxS4RlKCeCV0p+OhletJ+PbSbQOD4O95FVB7j0ppHKqhs2JDYLflZaA14AOFsuKsD4ew//Rl6QMgyyiaGht0/Do0Ah5aJjvzMJssKFnWOXwkGL+vVg7l/AVpZrLKVZ6u2mnYsU9LR6au21Kzj9UMlT3oWUiPMRAzJ+J460zo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=14.137.139.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.18.186.51]) by frasgout12.his.huawei.com (SkyGuard) with ESMTP id 4X3fSc5XVbz9v7Jb; Wed, 11 Sep 2024 20:06:56 +0800 (CST) Received: from mail02.huawei.com (unknown [7.182.16.47]) by mail.maildlp.com (Postfix) with ESMTP id DD54614086A; Wed, 11 Sep 2024 20:32:00 +0800 (CST) Received: from huaweicloud.com (unknown [10.204.63.22]) by APP1 (Coremail) with SMTP id LxC2BwD3hy+ijeFmnHu1AA--.60036S6; Wed, 11 Sep 2024 13:32:00 +0100 (CET) From: Roberto Sassu To: dhowells@redhat.com, dwmw2@infradead.org, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, zohar@linux.ibm.com, linux-integrity@vger.kernel.org, torvalds@linux-foundation.org, Roberto Sassu Subject: [PATCH v3 14/14] KEYS: Introduce load_pgp_public_keyring() Date: Wed, 11 Sep 2024 14:29:11 +0200 Message-Id: <20240911122911.1381864-15-roberto.sassu@huaweicloud.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> References: <20240911122911.1381864-1-roberto.sassu@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-CM-TRANSID: LxC2BwD3hy+ijeFmnHu1AA--.60036S6 X-Coremail-Antispam: 1UD129KBjvJXoWxJF1DZryrGFWkCF1rAF18Krg_yoWrZF45p3 yvyr1fKr4xtr1fArWfGF1UWrW5Cw1vkry2gw13Cw43AFWDKFy5ArsrKFs09ay5Wr98Zr1F v3yvqr1a9w1UA3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPlb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW8JVW5JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv6xkF7I0E 14v26r4UJVWxJr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrV C2j2WlYx0E2Ix0cI8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE 7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwACI402YVCY1x02628vn2kIc2xKxwCY1x0262 kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s02 6c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw 0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVW8JVW5JwCI42IY6xIIjxv20xvE c7CjxVAFwI0_Gr1j6F4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aV AFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8Jr0_Cr1UYxBIdaVFxhVjvjDU0xZF pf9x07Udl1kUUUUU= X-CM-SenderInfo: purev21wro2thvvxqx5xdzvxpfor3voofrz/1tbiAQADBGbg-HQH5gAAsp From: Roberto Sassu Preload PGP keys from 'pubring.gpg', placed in certs/ of the kernel source directory. Signed-off-by: Roberto Sassu --- certs/Kconfig | 11 +++++++++++ certs/Makefile | 7 +++++++ certs/system_certificates.S | 18 ++++++++++++++++++ certs/system_keyring.c | 23 +++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/certs/Kconfig b/certs/Kconfig index 78307dc25559..9b7ece1e45fa 100644 --- a/certs/Kconfig +++ b/certs/Kconfig @@ -154,4 +154,15 @@ config SYSTEM_BLACKLIST_AUTH_UPDATE keyring. The PKCS#7 signature of the description is set in the key payload. Blacklist keys cannot be removed. +config PGP_PRELOAD_PUBLIC_KEYS + bool "Preload PGP public keys" + depends on SYSTEM_TRUSTED_KEYRING + select PGP_PRELOAD + default n + help + Load at boot time the PGP public keys from a reserved area (populated + with the content of 'certs/pubring.gpg' provided at kernel build + time), and add them to the built-in keyring. Invalid keys are ignored + and the loading continues. + endmenu diff --git a/certs/Makefile b/certs/Makefile index 1094e3860c2a..7a3d68441e09 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -31,6 +31,13 @@ $(obj)/system_certificates.o: $(obj)/x509_certificate_list $(obj)/x509_certificate_list: $(CONFIG_SYSTEM_TRUSTED_KEYS) $(obj)/extract-cert FORCE $(call if_changed,extract_certs) +ifdef CONFIG_PGP_PRELOAD_PUBLIC_KEYS +ifeq ($(shell ls $(srctree)/certs/pubring.gpg 2> /dev/null), $(srctree)/certs/pubring.gpg) +AFLAGS_system_certificates.o := -DHAVE_PUBRING_GPG +$(obj)/system_certificates.o: $(srctree)/certs/pubring.gpg +endif +endif + targets += x509_certificate_list # If module signing is requested, say by allyesconfig, but a key has not been diff --git a/certs/system_certificates.S b/certs/system_certificates.S index 003e25d4a17e..b3cbf0811e3f 100644 --- a/certs/system_certificates.S +++ b/certs/system_certificates.S @@ -44,3 +44,21 @@ module_cert_size: #else .long __module_cert_end - __module_cert_start #endif + + .align 8 + .globl pgp_public_keys +pgp_public_keys: +__pgp_key_list_start: +#ifdef HAVE_PUBRING_GPG + .incbin "certs/pubring.gpg" +#endif +__pgp_key_list_end: + + .align 8 + .globl pgp_public_keys_size +pgp_public_keys_size: +#ifdef CONFIG_64BIT + .quad __pgp_key_list_end - __pgp_key_list_start +#else + .long __pgp_key_list_end - __pgp_key_list_start +#endif diff --git a/certs/system_keyring.c b/certs/system_keyring.c index f132773c6096..357d52d1d250 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -32,6 +32,10 @@ static struct key *platform_trusted_keys; extern __initconst const u8 system_certificate_list[]; extern __initconst const unsigned long system_certificate_list_size; extern __initconst const unsigned long module_cert_size; +#ifdef CONFIG_PGP_PRELOAD_PUBLIC_KEYS +extern __initconst const u8 pgp_public_keys[]; +extern __initconst const unsigned long pgp_public_keys_size; +#endif /** * restrict_link_by_builtin_trusted - Restrict keyring addition by built-in CA @@ -268,6 +272,15 @@ __init int load_module_cert(struct key *keyring) if (!IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG)) return 0; +#ifdef CONFIG_PGP_PRELOAD_PUBLIC_KEYS + pr_notice("Load PGP public keys to keyring %s\n", keyring->description); + + if (preload_pgp_keys(pgp_public_keys, + pgp_public_keys_size, + keyring) < 0) + pr_err("Can't load PGP public keys\n"); +#endif + pr_notice("Loading compiled-in module X.509 certificates\n"); return x509_load_certificate_list(system_certificate_list, @@ -292,6 +305,16 @@ static __init int load_system_certificate_list(void) size = system_certificate_list_size - module_cert_size; #endif +#ifdef CONFIG_PGP_PRELOAD_PUBLIC_KEYS + pr_notice("Load PGP public keys to keyring %s\n", + builtin_trusted_keys->description); + + if (preload_pgp_keys(pgp_public_keys, + pgp_public_keys_size, + builtin_trusted_keys) < 0) + pr_err("Can't load PGP public keys\n"); +#endif + return x509_load_certificate_list(p, size, builtin_trusted_keys); } late_initcall(load_system_certificate_list);