Commit 43d4042e authored by David Howells's avatar David Howells Committed by zgzxx
Browse files

KEYS: Provide a function to load keys from a PGP keyring blob

euleros inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I91FSN


CVE: NA

-------------------------------------------------

Provide a function to load keys from a PGP keyring blob for use in
initialising the module signing key keyring:

	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 module signing keyring has been
loaded:

383a00c1 I------     1 perm 1f030000     0     0 asymmetri \
				Red Hat, Inc. dbeca166: PGP.DSA dbeca166 []

Thanks to Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> for some
pointing out some errors.

Changelog

v0:
- avoid Kconfig circular dependency (Roberto Sassu)
- modify flags passed to key_create_or_update() (Roberto Sassu)
- don't process Public-Subkey packets (Roberto Sassu)
v5:
- fix checkpatch warning MISSING_EOF_NEWLINE in
  pgp_preload.c (zhangguangzhi)

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Co-developed-by: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarTianxing Zhang <zhangtianxing3@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Signed-off-by: default avatarzhoushuiqing <zhoushuiqing2@huawei.com>
Signed-off-by: default avatarzhangguangzhi <zhangguangzhi3@huawei.com>
parent ee32635f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -103,4 +103,12 @@ 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_PRELOAD
	bool "PGP public key preloading facility"
	select PGP_KEY_PARSER
	help
	  This option provides a facility for the kernel to preload PGP-wrapped
	  bundles of keys during boot.  It is used by module signing to load
	  the module signing keys for example.

endif # ASYMMETRIC_KEY_TYPE
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,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 := \
+124 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Cryptographic key request handling
 *
 * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public Licence
 * as published by the Free Software Foundation; either version
 * 2 of the Licence, or (at your option) any later version.
 *
 * See Documentation/security/keys-crypto.txt
 */

#ifdef CONFIG_PGP_PRELOAD

#include <linux/module.h>
#include <linux/key.h>
#include <linux/pgplib.h>
#include <linux/pgp.h>
#include <linux/err.h>
#include <keys/asymmetric-type.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 int __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))
		return PTR_ERR(key);

	pr_notice("Loaded PGP key '%s'\n",
		  key_ref_to_ptr(key)->description);

	key_ref_put(key);
	return 0;
}

/*
 * 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);
	int ret;

	if (ctx->found_key) {
		ctx->key_end = data - headerlen;
		ret = create_pgp_key(ctx);
		if (ret < 0)
			return ret;
	}

	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;
		return create_pgp_key(&ctx);
	}
	return 0;
}

#endif /* CONFIG_PGP_PRELOAD */
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#ifdef CONFIG_PGP_LIBRARY

#include <linux/types.h>
#include <linux/key.h>

struct pgp_key_ID {
	u8 id[8];
@@ -215,5 +216,8 @@ enum pgp_literal_data_format {
	PGP_LIT_FORMAT_TEXT_UTF8		= 0x75,
};

int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
			    struct key *keyring);

#endif /* CONFIG_PGP_LIBRARY */
#endif /* _LINUX_PGP_H */