mbox series

[v3,00/14] KEYS: Add support for PGP keys and signatures

Message ID 20240911122911.1381864-1-roberto.sassu@huaweicloud.com
Headers show
Series KEYS: Add support for PGP keys and signatures | expand

Message

Roberto Sassu Sept. 11, 2024, 12:28 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

Support for PGP keys and signatures was proposed by David long time ago,
before the decision of using PKCS#7 for kernel modules signatures
verification was made. After that, there has been not enough interest to
support PGP too.

Lately, there is renewed interest in supporting PGP keys and signatures for
the following use cases:

- EFI variables in modern Lenovo laptops are in PGP form:
  https://lore.kernel.org/keyrings/2493611.1723748374@warthog.procyon.org.uk/

- Appraisal of RPM package headers for integrity check
  https://lore.kernel.org/linux-integrity/20240905152512.3781098-1-roberto.sassu@huaweicloud.com/


To make these use cases possible, introduce support for PGP keys and
signatures in the kernel, and load provided PGP keys (e.g. Linux
distribution own PGP keys) in the built-in keyring and .ima keyrings.

This feature does not interfere with existing signature verification
mechanisms, such as the one for kernel modules. One has to explicitly call
verify_pgp_signature() to take advantage of it.

For the envisioned use cases, PGP operations cannot be done in user space,
since the consumers are in the kernel itself (Integrity Digest Cache and
IMA). Also they cannot be done in a trusted initial ram disk, since PGP
operations can occur also while the system is running (e.g. after software
package installation).

In addition to the original version of the patch set, also introduce
support for signature verification of PGP keys, so that those keys can be
added to keyrings with a signature-based restriction (e.g. .ima). PGP keys
are searched with partial IDs, provided with signature subtype 16 (Issuer).
However, due to the possibility of ID collisions, the key_or_keyring
restriction is not supported.

The patch set includes two preliminary patches: patch 1 introduces
mpi_key_length(), to get the number of bits and bytes of an MPI; patch 2
introduces rsa_parse_priv_key_raw() and rsa_parse_pub_key_raw(), to parse
an RSA key in RAW format if the ASN.1 parser returns an error.

Patches 3-5 introduce the library necessary to parse PGP keys and
signatures, whose support is added with patches 6-10. Patch 11 introduces
verify_pgp_signature() to be used by kernel subsystems (e.g. IMA). Patch 12
is for testing of PGP signatures. Finally, patches 13-14 allow loading a
set of PGP keys from a supplied blob at boot time.

Changelog

v2 [3]:
- Fix description of verify_pgp_signature()
- Change references from RFC 4880 to RFC 9580 (suggested by Jonathan
  McDowell)
- Remove support for v2 and v3 PGP keys (suggested by Jonathan McDowell)
- Explain better CONFIG_PGP_TEST_KEY
- Add MODULE_DESCRIPTION() for all kernel modules (suggested by Jeff
  Johnson)
- Don't fill capabilities and MPIs for unsupported key algorithms
- Check if there is enough data when parsing PGP key MPIs and RSA RAW keys
- Fix style issues
- Fix debug messages in pgp_request_asymmetric_key()
- Search verification key in the secondary keyring for the pgp_test key
  type

v1 [2]:
- Remove quiet_cmd_extract_certs (redundant, likely leftover from
  conflict resolution)
- Load PGP keys embedded in the kernel image within load_module_cert()
  and load_system_certificate_list(), instead of using a separate initcall
- Style bug fixes found by checkpatch.pl
- Add <crypto/pgp.h> include in crypto/asymmetric_keys/pgp_preload.c, to
  remove no previous prototype warning
- Correctly check returned tfm in pgp_generate_fingerprint()
- Fix printing message in pgp_generate_fingerprint()
- Don't create a public key if the key blob does not contain a PGP key
  packet
- Remove unused pgp_pubkey_hash array
- Set KEY_EFLAG_DIGITALSIG key flag if the key has the capability
- Allow PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY signature type (for key sigs)
- Add is_key_sig parameter to pgp_sig_get_sig() to ensure the key
  signature type is PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY or
  PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY

v0 [1]:
- style fixes
- move include/linux/pgp.h and pgplib.h to crypto/asymmetric_keys
- introduce verify_pgp_signature()
- replace KEY_ALLOC_TRUSTED flag with KEY_ALLOC_BUILT_IN
- don't fetch PGP subkeys
- drop support for DSA
- store number of MPIs in pgp_key_algo_p_num_mpi array
- replace dynamic memory allocations with static ones in
  pgp_generate_fingerprint()
- store only keys with capability of verifying signatures
- remember selection of PGP signature packet and don't repeat parsing
- move search of the PGP key to verify the signature from the beginning
  to the end of the verification process (to be similar with PKCS#7)
- don't retry key search in the session keyring from the signature
  verification code, let the caller pass the desired keyring
- for the PGP signature test key type, retry the key search in the session
  keyring
- retry key search in restrict_link_by_signature() with a partial ID
  (provided in the PGP signature)

[1] https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git/log/?h=pgp-parser
[2] https://lore.kernel.org/linux-integrity/20220111180318.591029-1-roberto.sassu@huawei.com/
[3] https://lore.kernel.org/linux-integrity/20240818165756.629203-1-roberto.sassu@huaweicloud.com/

David Howells (8):
  PGPLIB: PGP definitions (RFC 9580)
  PGPLIB: Basic packet parser
  PGPLIB: Signature parser
  KEYS: PGP data parser
  KEYS: Provide PGP key description autogeneration
  KEYS: PGP-based public key signature verification
  PGP: Provide a key type for testing PGP signatures
  KEYS: Provide a function to load keys from a PGP keyring blob

Roberto Sassu (6):
  mpi: Introduce mpi_key_length()
  rsa: add parser of raw format
  KEYS: Retry asym key search with partial ID in
    restrict_link_by_signature()
  KEYS: Calculate key digest and get signature of the key
  verification: introduce verify_pgp_signature()
  KEYS: Introduce load_pgp_public_keyring()

 MAINTAINERS                             |   1 +
 certs/Kconfig                           |  11 +
 certs/Makefile                          |   7 +
 certs/system_certificates.S             |  18 +
 certs/system_keyring.c                  |  94 ++++
 crypto/asymmetric_keys/Kconfig          |  39 ++
 crypto/asymmetric_keys/Makefile         |  13 +
 crypto/asymmetric_keys/pgp.h            | 216 +++++++++
 crypto/asymmetric_keys/pgp_library.c    | 610 ++++++++++++++++++++++++
 crypto/asymmetric_keys/pgp_parser.h     |  18 +
 crypto/asymmetric_keys/pgp_preload.c    | 111 +++++
 crypto/asymmetric_keys/pgp_public_key.c | 482 +++++++++++++++++++
 crypto/asymmetric_keys/pgp_signature.c  | 510 ++++++++++++++++++++
 crypto/asymmetric_keys/pgp_test_key.c   | 131 +++++
 crypto/asymmetric_keys/pgplib.h         |  74 +++
 crypto/asymmetric_keys/restrict.c       |  10 +-
 crypto/rsa.c                            |  14 +-
 crypto/rsa_helper.c                     |  83 +++-
 include/crypto/internal/rsa.h           |   6 +
 include/crypto/pgp.h                    |  36 ++
 include/linux/mpi.h                     |   2 +
 include/linux/verification.h            |  23 +
 lib/crypto/mpi/mpicoder.c               |  33 +-
 23 files changed, 2527 insertions(+), 15 deletions(-)
 create mode 100644 crypto/asymmetric_keys/pgp.h
 create mode 100644 crypto/asymmetric_keys/pgp_library.c
 create mode 100644 crypto/asymmetric_keys/pgp_parser.h
 create mode 100644 crypto/asymmetric_keys/pgp_preload.c
 create mode 100644 crypto/asymmetric_keys/pgp_public_key.c
 create mode 100644 crypto/asymmetric_keys/pgp_signature.c
 create mode 100644 crypto/asymmetric_keys/pgp_test_key.c
 create mode 100644 crypto/asymmetric_keys/pgplib.h
 create mode 100644 include/crypto/pgp.h

Comments

Jarkko Sakkinen Sept. 12, 2024, 1:26 p.m. UTC | #1
On Wed Sep 11, 2024 at 3:28 PM EEST, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Introduce the new function to get the number of bits and bytes from an MPI.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>  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);

"_arg" - what is the point of this?

>  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);

BR, Jarkko
Jarkko Sakkinen Sept. 12, 2024, 1:57 p.m. UTC | #2
On Wed Sep 11, 2024 at 3:29 PM EEST, Roberto Sassu wrote:
> From: David Howells <dhowells@redhat.com>
>
> 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 <dhowells@redhat.com>
> Co-developed-by: Roberto Sassu <roberto.sassu@huawei.com>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
>  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)
/* 
 * 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 <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#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;

Move the last declaration as the first declaration, makes more
readable (reverse christmas tree order).

I don't have time to go this patch fully for this round but I
saw some other similar nits below.

> +
> +	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);


BR, Jarkko
Herbert Xu Sept. 13, 2024, 4:45 a.m. UTC | #3
Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
>
> For the envisioned use cases, PGP operations cannot be done in user space,
> since the consumers are in the kernel itself (Integrity Digest Cache and
> IMA). Also they cannot be done in a trusted initial ram disk, since PGP
> operations can occur also while the system is running (e.g. after software
> package installation).

Does this address Linus's objections? If not then we cannot proceed.

Personally I don't think the argument above holds water.  With
IPsec we had a similar issue of authenticating untrusted peers
using public key cryptography.  In that case we successfully
delegated the task to user-space and it is still how it works
to this day.

A user-space daemon dedicated to public key crypto seems equally
applicable to your scenario.

The original application that brought public key crypto into the
kernel was module loading.  If we really wanted to we could extend
the user-space verification to modules too and perhaps kick all
public key crypto out of the kernel.

The complexity and lack of reviewer attention in this area means
that we're more likely to introduce security holes into the kernel
with such code.

Cheers,
Jarkko Sakkinen Sept. 14, 2024, 11:29 a.m. UTC | #4
On Fri Sep 13, 2024 at 7:45 AM EEST, Herbert Xu wrote:
> Roberto Sassu <roberto.sassu@huaweicloud.com> wrote:
> >
> > For the envisioned use cases, PGP operations cannot be done in user space,
> > since the consumers are in the kernel itself (Integrity Digest Cache and
> > IMA). Also they cannot be done in a trusted initial ram disk, since PGP
> > operations can occur also while the system is running (e.g. after software
> > package installation).
>
> Does this address Linus's objections? If not then we cannot proceed.

I don't get why integrity digest cache is brought up in patch set
discussion in the first place. It is RFC patch set. It is misleading
to bring up everywhere as it was something we would need to take in
the account.

Let's worry about that once it is even a feature.

BR, Jarkko