162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * DIAG 0x320 support and certificate store handling
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright IBM Corp. 2023
662306a36Sopenharmony_ci * Author(s):	Anastasia Eskova <anastasia.eskova@ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/fs.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/key-type.h>
1762306a36Sopenharmony_ci#include <linux/key.h>
1862306a36Sopenharmony_ci#include <linux/keyctl.h>
1962306a36Sopenharmony_ci#include <linux/kobject.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/seq_file.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/sysfs.h>
2462306a36Sopenharmony_ci#include <crypto/sha2.h>
2562306a36Sopenharmony_ci#include <keys/user-type.h>
2662306a36Sopenharmony_ci#include <asm/debug.h>
2762306a36Sopenharmony_ci#include <asm/diag.h>
2862306a36Sopenharmony_ci#include <asm/ebcdic.h>
2962306a36Sopenharmony_ci#include <asm/sclp.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define DIAG_MAX_RETRIES		10
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define VCE_FLAGS_VALID_MASK		0x80
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define ISM_LEN_DWORDS			4
3662306a36Sopenharmony_ci#define VCSSB_LEN_BYTES			128
3762306a36Sopenharmony_ci#define VCSSB_LEN_NO_CERTS		4
3862306a36Sopenharmony_ci#define VCB_LEN_NO_CERTS		64
3962306a36Sopenharmony_ci#define VC_NAME_LEN_BYTES		64
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define CERT_STORE_KEY_TYPE_NAME	"cert_store_key"
4262306a36Sopenharmony_ci#define CERT_STORE_KEYRING_NAME		"cert_store"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic debug_info_t *cert_store_dbf;
4562306a36Sopenharmony_cistatic debug_info_t *cert_store_hexdump;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define pr_dbf_msg(fmt, ...) \
4862306a36Sopenharmony_ci	debug_sprintf_event(cert_store_dbf, 3, fmt "\n", ## __VA_ARGS__)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cienum diag320_subcode {
5162306a36Sopenharmony_ci	DIAG320_SUBCODES	= 0,
5262306a36Sopenharmony_ci	DIAG320_STORAGE		= 1,
5362306a36Sopenharmony_ci	DIAG320_CERT_BLOCK	= 2,
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cienum diag320_rc {
5762306a36Sopenharmony_ci	DIAG320_RC_OK		= 0x0001,
5862306a36Sopenharmony_ci	DIAG320_RC_CS_NOMATCH	= 0x0306,
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Verification Certificates Store Support Block (VCSSB). */
6262306a36Sopenharmony_cistruct vcssb {
6362306a36Sopenharmony_ci	u32 vcssb_length;
6462306a36Sopenharmony_ci	u8  pad_0x04[3];
6562306a36Sopenharmony_ci	u8  version;
6662306a36Sopenharmony_ci	u8  pad_0x08[8];
6762306a36Sopenharmony_ci	u32 cs_token;
6862306a36Sopenharmony_ci	u8  pad_0x14[12];
6962306a36Sopenharmony_ci	u16 total_vc_index_count;
7062306a36Sopenharmony_ci	u16 max_vc_index_count;
7162306a36Sopenharmony_ci	u8  pad_0x24[28];
7262306a36Sopenharmony_ci	u32 max_vce_length;
7362306a36Sopenharmony_ci	u32 max_vcxe_length;
7462306a36Sopenharmony_ci	u8  pad_0x48[8];
7562306a36Sopenharmony_ci	u32 max_single_vcb_length;
7662306a36Sopenharmony_ci	u32 total_vcb_length;
7762306a36Sopenharmony_ci	u32 max_single_vcxb_length;
7862306a36Sopenharmony_ci	u32 total_vcxb_length;
7962306a36Sopenharmony_ci	u8  pad_0x60[32];
8062306a36Sopenharmony_ci} __packed __aligned(8);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Verification Certificate Entry (VCE) Header. */
8362306a36Sopenharmony_cistruct vce_header {
8462306a36Sopenharmony_ci	u32 vce_length;
8562306a36Sopenharmony_ci	u8  flags;
8662306a36Sopenharmony_ci	u8  key_type;
8762306a36Sopenharmony_ci	u16 vc_index;
8862306a36Sopenharmony_ci	u8  vc_name[VC_NAME_LEN_BYTES]; /* EBCDIC */
8962306a36Sopenharmony_ci	u8  vc_format;
9062306a36Sopenharmony_ci	u8  pad_0x49;
9162306a36Sopenharmony_ci	u16 key_id_length;
9262306a36Sopenharmony_ci	u8  pad_0x4c;
9362306a36Sopenharmony_ci	u8  vc_hash_type;
9462306a36Sopenharmony_ci	u16 vc_hash_length;
9562306a36Sopenharmony_ci	u8  pad_0x50[4];
9662306a36Sopenharmony_ci	u32 vc_length;
9762306a36Sopenharmony_ci	u8  pad_0x58[8];
9862306a36Sopenharmony_ci	u16 vc_hash_offset;
9962306a36Sopenharmony_ci	u16 vc_offset;
10062306a36Sopenharmony_ci	u8  pad_0x64[28];
10162306a36Sopenharmony_ci} __packed __aligned(4);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Verification Certificate Block (VCB) Header. */
10462306a36Sopenharmony_cistruct vcb_header {
10562306a36Sopenharmony_ci	u32 vcb_input_length;
10662306a36Sopenharmony_ci	u8  pad_0x04[4];
10762306a36Sopenharmony_ci	u16 first_vc_index;
10862306a36Sopenharmony_ci	u16 last_vc_index;
10962306a36Sopenharmony_ci	u32 pad_0x0c;
11062306a36Sopenharmony_ci	u32 cs_token;
11162306a36Sopenharmony_ci	u8  pad_0x14[12];
11262306a36Sopenharmony_ci	u32 vcb_output_length;
11362306a36Sopenharmony_ci	u8  pad_0x24[3];
11462306a36Sopenharmony_ci	u8  version;
11562306a36Sopenharmony_ci	u16 stored_vc_count;
11662306a36Sopenharmony_ci	u16 remaining_vc_count;
11762306a36Sopenharmony_ci	u8  pad_0x2c[20];
11862306a36Sopenharmony_ci} __packed __aligned(4);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* Verification Certificate Block (VCB). */
12162306a36Sopenharmony_cistruct vcb {
12262306a36Sopenharmony_ci	struct vcb_header vcb_hdr;
12362306a36Sopenharmony_ci	u8 vcb_buf[];
12462306a36Sopenharmony_ci} __packed __aligned(4);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* Verification Certificate Entry (VCE). */
12762306a36Sopenharmony_cistruct vce {
12862306a36Sopenharmony_ci	struct vce_header vce_hdr;
12962306a36Sopenharmony_ci	u8 cert_data_buf[];
13062306a36Sopenharmony_ci} __packed __aligned(4);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic void cert_store_key_describe(const struct key *key, struct seq_file *m)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	char ascii[VC_NAME_LEN_BYTES + 1];
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/*
13762306a36Sopenharmony_ci	 * First 64 bytes of the key description is key name in EBCDIC CP 500.
13862306a36Sopenharmony_ci	 * Convert it to ASCII for displaying in /proc/keys.
13962306a36Sopenharmony_ci	 */
14062306a36Sopenharmony_ci	strscpy(ascii, key->description, sizeof(ascii));
14162306a36Sopenharmony_ci	EBCASC_500(ascii, VC_NAME_LEN_BYTES);
14262306a36Sopenharmony_ci	seq_puts(m, ascii);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	seq_puts(m, &key->description[VC_NAME_LEN_BYTES]);
14562306a36Sopenharmony_ci	if (key_is_positive(key))
14662306a36Sopenharmony_ci		seq_printf(m, ": %u", key->datalen);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * Certificate store key type takes over properties of
15162306a36Sopenharmony_ci * user key but cannot be updated.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_cistatic struct key_type key_type_cert_store_key = {
15462306a36Sopenharmony_ci	.name		= CERT_STORE_KEY_TYPE_NAME,
15562306a36Sopenharmony_ci	.preparse	= user_preparse,
15662306a36Sopenharmony_ci	.free_preparse	= user_free_preparse,
15762306a36Sopenharmony_ci	.instantiate	= generic_key_instantiate,
15862306a36Sopenharmony_ci	.revoke		= user_revoke,
15962306a36Sopenharmony_ci	.destroy	= user_destroy,
16062306a36Sopenharmony_ci	.describe	= cert_store_key_describe,
16162306a36Sopenharmony_ci	.read		= user_read,
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* Logging functions. */
16562306a36Sopenharmony_cistatic void pr_dbf_vcb(const struct vcb *b)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	pr_dbf_msg("VCB Header:");
16862306a36Sopenharmony_ci	pr_dbf_msg("vcb_input_length: %d", b->vcb_hdr.vcb_input_length);
16962306a36Sopenharmony_ci	pr_dbf_msg("first_vc_index: %d", b->vcb_hdr.first_vc_index);
17062306a36Sopenharmony_ci	pr_dbf_msg("last_vc_index: %d", b->vcb_hdr.last_vc_index);
17162306a36Sopenharmony_ci	pr_dbf_msg("cs_token: %d", b->vcb_hdr.cs_token);
17262306a36Sopenharmony_ci	pr_dbf_msg("vcb_output_length: %d", b->vcb_hdr.vcb_output_length);
17362306a36Sopenharmony_ci	pr_dbf_msg("version: %d", b->vcb_hdr.version);
17462306a36Sopenharmony_ci	pr_dbf_msg("stored_vc_count: %d", b->vcb_hdr.stored_vc_count);
17562306a36Sopenharmony_ci	pr_dbf_msg("remaining_vc_count: %d", b->vcb_hdr.remaining_vc_count);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void pr_dbf_vce(const struct vce *e)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	unsigned char vc_name[VC_NAME_LEN_BYTES + 1];
18162306a36Sopenharmony_ci	char log_string[VC_NAME_LEN_BYTES + 40];
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	pr_dbf_msg("VCE Header:");
18462306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vce_length: %d", e->vce_hdr.vce_length);
18562306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.flags: %d", e->vce_hdr.flags);
18662306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.key_type: %d", e->vce_hdr.key_type);
18762306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_index: %d", e->vce_hdr.vc_index);
18862306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_format: %d", e->vce_hdr.vc_format);
18962306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.key_id_length: %d", e->vce_hdr.key_id_length);
19062306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_hash_type: %d", e->vce_hdr.vc_hash_type);
19162306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_hash_length: %d", e->vce_hdr.vc_hash_length);
19262306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_hash_offset: %d", e->vce_hdr.vc_hash_offset);
19362306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_length: %d", e->vce_hdr.vc_length);
19462306a36Sopenharmony_ci	pr_dbf_msg("vce_hdr.vc_offset: %d", e->vce_hdr.vc_offset);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Certificate name in ASCII. */
19762306a36Sopenharmony_ci	memcpy(vc_name, e->vce_hdr.vc_name, VC_NAME_LEN_BYTES);
19862306a36Sopenharmony_ci	EBCASC_500(vc_name, VC_NAME_LEN_BYTES);
19962306a36Sopenharmony_ci	vc_name[VC_NAME_LEN_BYTES] = '\0';
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	snprintf(log_string, sizeof(log_string),
20262306a36Sopenharmony_ci		 "index: %d vce_hdr.vc_name (ASCII): %s",
20362306a36Sopenharmony_ci		 e->vce_hdr.vc_index, vc_name);
20462306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, log_string);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Certificate data. */
20762306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "VCE: Certificate data start");
20862306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3, (u8 *)e->cert_data_buf, 128);
20962306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "VCE: Certificate data end");
21062306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3,
21162306a36Sopenharmony_ci		    (u8 *)e->cert_data_buf + e->vce_hdr.vce_length - 128, 128);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic void pr_dbf_vcssb(const struct vcssb *s)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "DIAG320 Subcode1");
21762306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3, (u8 *)s, VCSSB_LEN_BYTES);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	pr_dbf_msg("VCSSB:");
22062306a36Sopenharmony_ci	pr_dbf_msg("vcssb_length: %u", s->vcssb_length);
22162306a36Sopenharmony_ci	pr_dbf_msg("version: %u", s->version);
22262306a36Sopenharmony_ci	pr_dbf_msg("cs_token: %u", s->cs_token);
22362306a36Sopenharmony_ci	pr_dbf_msg("total_vc_index_count: %u", s->total_vc_index_count);
22462306a36Sopenharmony_ci	pr_dbf_msg("max_vc_index_count: %u", s->max_vc_index_count);
22562306a36Sopenharmony_ci	pr_dbf_msg("max_vce_length: %u", s->max_vce_length);
22662306a36Sopenharmony_ci	pr_dbf_msg("max_vcxe_length: %u", s->max_vce_length);
22762306a36Sopenharmony_ci	pr_dbf_msg("max_single_vcb_length: %u", s->max_single_vcb_length);
22862306a36Sopenharmony_ci	pr_dbf_msg("total_vcb_length: %u", s->total_vcb_length);
22962306a36Sopenharmony_ci	pr_dbf_msg("max_single_vcxb_length: %u", s->max_single_vcxb_length);
23062306a36Sopenharmony_ci	pr_dbf_msg("total_vcxb_length: %u", s->total_vcxb_length);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic int __diag320(unsigned long subcode, void *addr)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	union register_pair rp = { .even = (unsigned long)addr, };
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	asm volatile(
23862306a36Sopenharmony_ci		"	diag	%[rp],%[subcode],0x320\n"
23962306a36Sopenharmony_ci		"0:	nopr	%%r7\n"
24062306a36Sopenharmony_ci		EX_TABLE(0b, 0b)
24162306a36Sopenharmony_ci		: [rp] "+d" (rp.pair)
24262306a36Sopenharmony_ci		: [subcode] "d" (subcode)
24362306a36Sopenharmony_ci		: "cc", "memory");
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return rp.odd;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int diag320(unsigned long subcode, void *addr)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	diag_stat_inc(DIAG_STAT_X320);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return __diag320(subcode, addr);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Calculate SHA256 hash of the VCE certificate and compare it to hash stored in
25762306a36Sopenharmony_ci * VCE. Return -EINVAL if hashes don't match.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic int check_certificate_hash(const struct vce *vce)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	u8 hash[SHA256_DIGEST_SIZE];
26262306a36Sopenharmony_ci	u16 vc_hash_length;
26362306a36Sopenharmony_ci	u8 *vce_hash;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	vce_hash = (u8 *)vce + vce->vce_hdr.vc_hash_offset;
26662306a36Sopenharmony_ci	vc_hash_length = vce->vce_hdr.vc_hash_length;
26762306a36Sopenharmony_ci	sha256((u8 *)vce + vce->vce_hdr.vc_offset, vce->vce_hdr.vc_length, hash);
26862306a36Sopenharmony_ci	if (memcmp(vce_hash, hash, vc_hash_length) == 0)
26962306a36Sopenharmony_ci		return 0;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	pr_dbf_msg("SHA256 hash of received certificate does not match");
27262306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "VCE hash:");
27362306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3, vce_hash, SHA256_DIGEST_SIZE);
27462306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "Calculated hash:");
27562306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3, hash, SHA256_DIGEST_SIZE);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return -EINVAL;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int check_certificate_valid(const struct vce *vce)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	if (!(vce->vce_hdr.flags & VCE_FLAGS_VALID_MASK)) {
28362306a36Sopenharmony_ci		pr_dbf_msg("Certificate entry is invalid");
28462306a36Sopenharmony_ci		return -EINVAL;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci	if (vce->vce_hdr.vc_format != 1) {
28762306a36Sopenharmony_ci		pr_dbf_msg("Certificate format is not supported");
28862306a36Sopenharmony_ci		return -EINVAL;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci	if (vce->vce_hdr.vc_hash_type != 1) {
29162306a36Sopenharmony_ci		pr_dbf_msg("Hash type is not supported");
29262306a36Sopenharmony_ci		return -EINVAL;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return check_certificate_hash(vce);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic struct key *get_user_session_keyring(void)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	key_ref_t us_keyring_ref;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	us_keyring_ref = lookup_user_key(KEY_SPEC_USER_SESSION_KEYRING,
30362306a36Sopenharmony_ci					 KEY_LOOKUP_CREATE, KEY_NEED_LINK);
30462306a36Sopenharmony_ci	if (IS_ERR(us_keyring_ref)) {
30562306a36Sopenharmony_ci		pr_dbf_msg("Couldn't get user session keyring: %ld",
30662306a36Sopenharmony_ci			   PTR_ERR(us_keyring_ref));
30762306a36Sopenharmony_ci		return ERR_PTR(-ENOKEY);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	key_ref_put(us_keyring_ref);
31062306a36Sopenharmony_ci	return key_ref_to_ptr(us_keyring_ref);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/* Invalidate all keys from cert_store keyring. */
31462306a36Sopenharmony_cistatic int invalidate_keyring_keys(struct key *keyring)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	unsigned long num_keys, key_index;
31762306a36Sopenharmony_ci	size_t keyring_payload_len;
31862306a36Sopenharmony_ci	key_serial_t *key_array;
31962306a36Sopenharmony_ci	struct key *current_key;
32062306a36Sopenharmony_ci	int rc;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	keyring_payload_len = key_type_keyring.read(keyring, NULL, 0);
32362306a36Sopenharmony_ci	num_keys = keyring_payload_len / sizeof(key_serial_t);
32462306a36Sopenharmony_ci	key_array = kcalloc(num_keys, sizeof(key_serial_t), GFP_KERNEL);
32562306a36Sopenharmony_ci	if (!key_array)
32662306a36Sopenharmony_ci		return -ENOMEM;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	rc = key_type_keyring.read(keyring, (char *)key_array, keyring_payload_len);
32962306a36Sopenharmony_ci	if (rc != keyring_payload_len) {
33062306a36Sopenharmony_ci		pr_dbf_msg("Couldn't read keyring payload");
33162306a36Sopenharmony_ci		goto out;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	for (key_index = 0; key_index < num_keys; key_index++) {
33562306a36Sopenharmony_ci		current_key = key_lookup(key_array[key_index]);
33662306a36Sopenharmony_ci		pr_dbf_msg("Invalidating key %08x", current_key->serial);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		key_invalidate(current_key);
33962306a36Sopenharmony_ci		key_put(current_key);
34062306a36Sopenharmony_ci		rc = key_unlink(keyring, current_key);
34162306a36Sopenharmony_ci		if (rc) {
34262306a36Sopenharmony_ci			pr_dbf_msg("Couldn't unlink key %08x: %d", current_key->serial, rc);
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		}
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ciout:
34762306a36Sopenharmony_ci	kfree(key_array);
34862306a36Sopenharmony_ci	return rc;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic struct key *find_cs_keyring(void)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	key_ref_t cs_keyring_ref;
35462306a36Sopenharmony_ci	struct key *cs_keyring;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	cs_keyring_ref = keyring_search(make_key_ref(get_user_session_keyring(), true),
35762306a36Sopenharmony_ci					&key_type_keyring, CERT_STORE_KEYRING_NAME,
35862306a36Sopenharmony_ci					false);
35962306a36Sopenharmony_ci	if (!IS_ERR(cs_keyring_ref)) {
36062306a36Sopenharmony_ci		cs_keyring = key_ref_to_ptr(cs_keyring_ref);
36162306a36Sopenharmony_ci		key_ref_put(cs_keyring_ref);
36262306a36Sopenharmony_ci		goto found;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	/* Search default locations: thread, process, session keyrings */
36562306a36Sopenharmony_ci	cs_keyring = request_key(&key_type_keyring, CERT_STORE_KEYRING_NAME, NULL);
36662306a36Sopenharmony_ci	if (IS_ERR(cs_keyring))
36762306a36Sopenharmony_ci		return NULL;
36862306a36Sopenharmony_ci	key_put(cs_keyring);
36962306a36Sopenharmony_cifound:
37062306a36Sopenharmony_ci	return cs_keyring;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void cleanup_cs_keys(void)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct key *cs_keyring;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	cs_keyring = find_cs_keyring();
37862306a36Sopenharmony_ci	if (!cs_keyring)
37962306a36Sopenharmony_ci		return;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	pr_dbf_msg("Found cert_store keyring. Purging...");
38262306a36Sopenharmony_ci	/*
38362306a36Sopenharmony_ci	 * Remove cert_store_key_type in case invalidation
38462306a36Sopenharmony_ci	 * of old cert_store keys failed (= severe error).
38562306a36Sopenharmony_ci	 */
38662306a36Sopenharmony_ci	if (invalidate_keyring_keys(cs_keyring))
38762306a36Sopenharmony_ci		unregister_key_type(&key_type_cert_store_key);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	keyring_clear(cs_keyring);
39062306a36Sopenharmony_ci	key_invalidate(cs_keyring);
39162306a36Sopenharmony_ci	key_put(cs_keyring);
39262306a36Sopenharmony_ci	key_unlink(get_user_session_keyring(), cs_keyring);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic struct key *create_cs_keyring(void)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	static struct key *cs_keyring;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Cleanup previous cs_keyring and all associated keys if any. */
40062306a36Sopenharmony_ci	cleanup_cs_keys();
40162306a36Sopenharmony_ci	cs_keyring = keyring_alloc(CERT_STORE_KEYRING_NAME, GLOBAL_ROOT_UID,
40262306a36Sopenharmony_ci				   GLOBAL_ROOT_GID, current_cred(),
40362306a36Sopenharmony_ci				   (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ,
40462306a36Sopenharmony_ci				   KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_SET_KEEP,
40562306a36Sopenharmony_ci				   NULL, get_user_session_keyring());
40662306a36Sopenharmony_ci	if (IS_ERR(cs_keyring)) {
40762306a36Sopenharmony_ci		pr_dbf_msg("Can't allocate cert_store keyring");
40862306a36Sopenharmony_ci		return NULL;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	pr_dbf_msg("Successfully allocated cert_store keyring: %08x", cs_keyring->serial);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/*
41462306a36Sopenharmony_ci	 * In case a previous clean-up ran into an
41562306a36Sopenharmony_ci	 * error and unregistered key type.
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci	register_key_type(&key_type_cert_store_key);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return cs_keyring;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/*
42362306a36Sopenharmony_ci * Allocate memory and create key description in format
42462306a36Sopenharmony_ci * [key name in EBCDIC]:[VCE index]:[CS token].
42562306a36Sopenharmony_ci * Return a pointer to key description or NULL if memory
42662306a36Sopenharmony_ci * allocation failed. Memory should be freed by caller.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic char *get_key_description(struct vcssb *vcssb, const struct vce *vce)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	size_t len, name_len;
43162306a36Sopenharmony_ci	u32 cs_token;
43262306a36Sopenharmony_ci	char *desc;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	cs_token = vcssb->cs_token;
43562306a36Sopenharmony_ci	/* Description string contains "%64s:%05u:%010u\0". */
43662306a36Sopenharmony_ci	name_len = sizeof(vce->vce_hdr.vc_name);
43762306a36Sopenharmony_ci	len = name_len + 1 + 5 + 1 + 10 + 1;
43862306a36Sopenharmony_ci	desc = kmalloc(len, GFP_KERNEL);
43962306a36Sopenharmony_ci	if (!desc)
44062306a36Sopenharmony_ci		return NULL;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	memcpy(desc, vce->vce_hdr.vc_name, name_len);
44362306a36Sopenharmony_ci	snprintf(desc + name_len, len - name_len, ":%05u:%010u",
44462306a36Sopenharmony_ci		 vce->vce_hdr.vc_index, cs_token);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return desc;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci/*
45062306a36Sopenharmony_ci * Create a key of type "cert_store_key" using the data from VCE for key
45162306a36Sopenharmony_ci * payload and key description. Link the key to "cert_store" keyring.
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_cistatic int create_key_from_vce(struct vcssb *vcssb, struct vce *vce,
45462306a36Sopenharmony_ci			       struct key *keyring)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	key_ref_t newkey;
45762306a36Sopenharmony_ci	char *desc;
45862306a36Sopenharmony_ci	int rc;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	desc = get_key_description(vcssb, vce);
46162306a36Sopenharmony_ci	if (!desc)
46262306a36Sopenharmony_ci		return -ENOMEM;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	newkey = key_create_or_update(
46562306a36Sopenharmony_ci		make_key_ref(keyring, true), CERT_STORE_KEY_TYPE_NAME,
46662306a36Sopenharmony_ci		desc, (u8 *)vce + vce->vce_hdr.vc_offset,
46762306a36Sopenharmony_ci		vce->vce_hdr.vc_length,
46862306a36Sopenharmony_ci		(KEY_POS_ALL & ~KEY_POS_SETATTR)  | KEY_USR_VIEW | KEY_USR_READ,
46962306a36Sopenharmony_ci		KEY_ALLOC_NOT_IN_QUOTA);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	rc = PTR_ERR_OR_ZERO(newkey);
47262306a36Sopenharmony_ci	if (rc) {
47362306a36Sopenharmony_ci		pr_dbf_msg("Couldn't create a key from Certificate Entry (%d)", rc);
47462306a36Sopenharmony_ci		rc = -ENOKEY;
47562306a36Sopenharmony_ci		goto out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	key_ref_put(newkey);
47962306a36Sopenharmony_ciout:
48062306a36Sopenharmony_ci	kfree(desc);
48162306a36Sopenharmony_ci	return rc;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/* Get Verification Certificate Storage Size block with DIAG320 subcode2. */
48562306a36Sopenharmony_cistatic int get_vcssb(struct vcssb *vcssb)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	int diag320_rc;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	memset(vcssb, 0, sizeof(*vcssb));
49062306a36Sopenharmony_ci	vcssb->vcssb_length = VCSSB_LEN_BYTES;
49162306a36Sopenharmony_ci	diag320_rc = diag320(DIAG320_STORAGE, vcssb);
49262306a36Sopenharmony_ci	pr_dbf_vcssb(vcssb);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (diag320_rc != DIAG320_RC_OK) {
49562306a36Sopenharmony_ci		pr_dbf_msg("Diag 320 Subcode 1 returned bad RC: %04x", diag320_rc);
49662306a36Sopenharmony_ci		return -EIO;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	if (vcssb->vcssb_length == VCSSB_LEN_NO_CERTS) {
49962306a36Sopenharmony_ci		pr_dbf_msg("No certificates available for current configuration");
50062306a36Sopenharmony_ci		return -ENOKEY;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	return 0;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic u32 get_4k_mult_vcb_size(struct vcssb *vcssb)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	return round_up(vcssb->max_single_vcb_length, PAGE_SIZE);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/* Fill input fields of single-entry VCB that will be read by LPAR. */
51262306a36Sopenharmony_cistatic void fill_vcb_input(struct vcssb *vcssb, struct vcb *vcb, u16 index)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	memset(vcb, 0, sizeof(*vcb));
51562306a36Sopenharmony_ci	vcb->vcb_hdr.vcb_input_length = get_4k_mult_vcb_size(vcssb);
51662306a36Sopenharmony_ci	vcb->vcb_hdr.cs_token = vcssb->cs_token;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Request single entry. */
51962306a36Sopenharmony_ci	vcb->vcb_hdr.first_vc_index = index;
52062306a36Sopenharmony_ci	vcb->vcb_hdr.last_vc_index = index;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void extract_vce_from_sevcb(struct vcb *vcb, struct vce *vce)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct vce *extracted_vce;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	extracted_vce = (struct vce *)vcb->vcb_buf;
52862306a36Sopenharmony_ci	memcpy(vce, vcb->vcb_buf, extracted_vce->vce_hdr.vce_length);
52962306a36Sopenharmony_ci	pr_dbf_vce(vce);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic int get_sevcb(struct vcssb *vcssb, u16 index, struct vcb *vcb)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	int rc, diag320_rc;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	fill_vcb_input(vcssb, vcb, index);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	diag320_rc = diag320(DIAG320_CERT_BLOCK, vcb);
53962306a36Sopenharmony_ci	pr_dbf_msg("Diag 320 Subcode2 RC %2x", diag320_rc);
54062306a36Sopenharmony_ci	pr_dbf_vcb(vcb);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	switch (diag320_rc) {
54362306a36Sopenharmony_ci	case DIAG320_RC_OK:
54462306a36Sopenharmony_ci		rc = 0;
54562306a36Sopenharmony_ci		if (vcb->vcb_hdr.vcb_output_length == VCB_LEN_NO_CERTS) {
54662306a36Sopenharmony_ci			pr_dbf_msg("No certificate entry for index %u", index);
54762306a36Sopenharmony_ci			rc = -ENOKEY;
54862306a36Sopenharmony_ci		} else if (vcb->vcb_hdr.remaining_vc_count != 0) {
54962306a36Sopenharmony_ci			/* Retry on insufficient space. */
55062306a36Sopenharmony_ci			pr_dbf_msg("Couldn't get all requested certificates");
55162306a36Sopenharmony_ci			rc = -EAGAIN;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci	case DIAG320_RC_CS_NOMATCH:
55562306a36Sopenharmony_ci		pr_dbf_msg("Certificate Store token mismatch");
55662306a36Sopenharmony_ci		rc = -EAGAIN;
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	default:
55962306a36Sopenharmony_ci		pr_dbf_msg("Diag 320 Subcode2 returned bad rc (0x%4x)", diag320_rc);
56062306a36Sopenharmony_ci		rc = -EINVAL;
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	return rc;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/*
56862306a36Sopenharmony_ci * Allocate memory for single-entry VCB, get VCB via DIAG320 subcode 2 call,
56962306a36Sopenharmony_ci * extract VCE and create a key from its' certificate.
57062306a36Sopenharmony_ci */
57162306a36Sopenharmony_cistatic int create_key_from_sevcb(struct vcssb *vcssb, u16 index,
57262306a36Sopenharmony_ci				 struct key *keyring)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct vcb *vcb;
57562306a36Sopenharmony_ci	struct vce *vce;
57662306a36Sopenharmony_ci	int rc;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	rc = -ENOMEM;
57962306a36Sopenharmony_ci	vcb = vmalloc(get_4k_mult_vcb_size(vcssb));
58062306a36Sopenharmony_ci	vce = vmalloc(vcssb->max_single_vcb_length - sizeof(vcb->vcb_hdr));
58162306a36Sopenharmony_ci	if (!vcb || !vce)
58262306a36Sopenharmony_ci		goto out;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	rc = get_sevcb(vcssb, index, vcb);
58562306a36Sopenharmony_ci	if (rc)
58662306a36Sopenharmony_ci		goto out;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	extract_vce_from_sevcb(vcb, vce);
58962306a36Sopenharmony_ci	rc = check_certificate_valid(vce);
59062306a36Sopenharmony_ci	if (rc)
59162306a36Sopenharmony_ci		goto out;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	rc = create_key_from_vce(vcssb, vce, keyring);
59462306a36Sopenharmony_ci	if (rc)
59562306a36Sopenharmony_ci		goto out;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	pr_dbf_msg("Successfully created key from Certificate Entry %d", index);
59862306a36Sopenharmony_ciout:
59962306a36Sopenharmony_ci	vfree(vce);
60062306a36Sopenharmony_ci	vfree(vcb);
60162306a36Sopenharmony_ci	return rc;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/*
60562306a36Sopenharmony_ci * Request a single-entry VCB for each VCE available for the partition.
60662306a36Sopenharmony_ci * Create a key from it and link it to cert_store keyring. If no keys
60762306a36Sopenharmony_ci * could be created (i.e. VCEs were invalid) return -ENOKEY.
60862306a36Sopenharmony_ci */
60962306a36Sopenharmony_cistatic int add_certificates_to_keyring(struct vcssb *vcssb, struct key *keyring)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	int rc, index, count, added;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	count = 0;
61462306a36Sopenharmony_ci	added = 0;
61562306a36Sopenharmony_ci	/* Certificate Store entries indices start with 1 and have no gaps. */
61662306a36Sopenharmony_ci	for (index = 1; index < vcssb->total_vc_index_count + 1; index++) {
61762306a36Sopenharmony_ci		pr_dbf_msg("Creating key from VCE %u", index);
61862306a36Sopenharmony_ci		rc = create_key_from_sevcb(vcssb, index, keyring);
61962306a36Sopenharmony_ci		count++;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		if (rc == -EAGAIN)
62262306a36Sopenharmony_ci			return rc;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		if (rc)
62562306a36Sopenharmony_ci			pr_dbf_msg("Creating key from VCE %u failed (%d)", index, rc);
62662306a36Sopenharmony_ci		else
62762306a36Sopenharmony_ci			added++;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (added == 0) {
63162306a36Sopenharmony_ci		pr_dbf_msg("Processed %d entries. No keys created", count);
63262306a36Sopenharmony_ci		return -ENOKEY;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	pr_info("Added %d of %d keys to cert_store keyring", added, count);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/*
63862306a36Sopenharmony_ci	 * Do not allow to link more keys to certificate store keyring after all
63962306a36Sopenharmony_ci	 * the VCEs were processed.
64062306a36Sopenharmony_ci	 */
64162306a36Sopenharmony_ci	rc = keyring_restrict(make_key_ref(keyring, true), NULL, NULL);
64262306a36Sopenharmony_ci	if (rc)
64362306a36Sopenharmony_ci		pr_dbf_msg("Failed to set restriction to cert_store keyring (%d)", rc);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return 0;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/*
64962306a36Sopenharmony_ci * Check which DIAG320 subcodes are installed.
65062306a36Sopenharmony_ci * Return -ENOENT if subcodes 1 or 2 are not available.
65162306a36Sopenharmony_ci */
65262306a36Sopenharmony_cistatic int query_diag320_subcodes(void)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	unsigned long ism[ISM_LEN_DWORDS];
65562306a36Sopenharmony_ci	int rc;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	rc = diag320(0, ism);
65862306a36Sopenharmony_ci	if (rc != DIAG320_RC_OK) {
65962306a36Sopenharmony_ci		pr_dbf_msg("DIAG320 subcode query returned %04x", rc);
66062306a36Sopenharmony_ci		return -ENOENT;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	debug_text_event(cert_store_hexdump, 3, "DIAG320 Subcode 0");
66462306a36Sopenharmony_ci	debug_event(cert_store_hexdump, 3, ism, sizeof(ism));
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!test_bit_inv(1, ism) || !test_bit_inv(2, ism)) {
66762306a36Sopenharmony_ci		pr_dbf_msg("Not all required DIAG320 subcodes are installed");
66862306a36Sopenharmony_ci		return -ENOENT;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/*
67562306a36Sopenharmony_ci * Check if Certificate Store is supported by the firmware and DIAG320 subcodes
67662306a36Sopenharmony_ci * 1 and 2 are installed. Create cert_store keyring and link all certificates
67762306a36Sopenharmony_ci * available for the current partition to it as "cert_store_key" type
67862306a36Sopenharmony_ci * keys. On refresh or error invalidate cert_store keyring and destroy
67962306a36Sopenharmony_ci * all keys of "cert_store_key" type.
68062306a36Sopenharmony_ci */
68162306a36Sopenharmony_cistatic int fill_cs_keyring(void)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct key *cs_keyring;
68462306a36Sopenharmony_ci	struct vcssb *vcssb;
68562306a36Sopenharmony_ci	int rc;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	rc = -ENOMEM;
68862306a36Sopenharmony_ci	vcssb = kmalloc(VCSSB_LEN_BYTES, GFP_KERNEL);
68962306a36Sopenharmony_ci	if (!vcssb)
69062306a36Sopenharmony_ci		goto cleanup_keys;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	rc = -ENOENT;
69362306a36Sopenharmony_ci	if (!sclp.has_diag320) {
69462306a36Sopenharmony_ci		pr_dbf_msg("Certificate Store is not supported");
69562306a36Sopenharmony_ci		goto cleanup_keys;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	rc = query_diag320_subcodes();
69962306a36Sopenharmony_ci	if (rc)
70062306a36Sopenharmony_ci		goto cleanup_keys;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	rc = get_vcssb(vcssb);
70362306a36Sopenharmony_ci	if (rc)
70462306a36Sopenharmony_ci		goto cleanup_keys;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rc = -ENOMEM;
70762306a36Sopenharmony_ci	cs_keyring = create_cs_keyring();
70862306a36Sopenharmony_ci	if (!cs_keyring)
70962306a36Sopenharmony_ci		goto cleanup_keys;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	rc = add_certificates_to_keyring(vcssb, cs_keyring);
71262306a36Sopenharmony_ci	if (rc)
71362306a36Sopenharmony_ci		goto cleanup_cs_keyring;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	goto out;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cicleanup_cs_keyring:
71862306a36Sopenharmony_ci	key_put(cs_keyring);
71962306a36Sopenharmony_cicleanup_keys:
72062306a36Sopenharmony_ci	cleanup_cs_keys();
72162306a36Sopenharmony_ciout:
72262306a36Sopenharmony_ci	kfree(vcssb);
72362306a36Sopenharmony_ci	return rc;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic DEFINE_MUTEX(cs_refresh_lock);
72762306a36Sopenharmony_cistatic int cs_status_val = -1;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cistatic ssize_t cs_status_show(struct kobject *kobj,
73062306a36Sopenharmony_ci			      struct kobj_attribute *attr, char *buf)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	if (cs_status_val == -1)
73362306a36Sopenharmony_ci		return sysfs_emit(buf, "uninitialized\n");
73462306a36Sopenharmony_ci	else if (cs_status_val == 0)
73562306a36Sopenharmony_ci		return sysfs_emit(buf, "ok\n");
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return sysfs_emit(buf, "failed (%d)\n", cs_status_val);
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic struct kobj_attribute cs_status_attr = __ATTR_RO(cs_status);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic ssize_t refresh_store(struct kobject *kobj, struct kobj_attribute *attr,
74362306a36Sopenharmony_ci			     const char *buf, size_t count)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	int rc, retries;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	pr_dbf_msg("Refresh certificate store information requested");
74862306a36Sopenharmony_ci	rc = mutex_lock_interruptible(&cs_refresh_lock);
74962306a36Sopenharmony_ci	if (rc)
75062306a36Sopenharmony_ci		return rc;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	for (retries = 0; retries < DIAG_MAX_RETRIES; retries++) {
75362306a36Sopenharmony_ci		/* Request certificates from certificate store. */
75462306a36Sopenharmony_ci		rc = fill_cs_keyring();
75562306a36Sopenharmony_ci		if (rc)
75662306a36Sopenharmony_ci			pr_dbf_msg("Failed to refresh certificate store information (%d)", rc);
75762306a36Sopenharmony_ci		if (rc != -EAGAIN)
75862306a36Sopenharmony_ci			break;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci	cs_status_val = rc;
76162306a36Sopenharmony_ci	mutex_unlock(&cs_refresh_lock);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return rc ?: count;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic struct kobj_attribute refresh_attr = __ATTR_WO(refresh);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic const struct attribute *cert_store_attrs[] __initconst = {
76962306a36Sopenharmony_ci	&cs_status_attr.attr,
77062306a36Sopenharmony_ci	&refresh_attr.attr,
77162306a36Sopenharmony_ci	NULL,
77262306a36Sopenharmony_ci};
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic struct kobject *cert_store_kobj;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic int __init cert_store_init(void)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	int rc = -ENOMEM;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	cert_store_dbf = debug_register("cert_store_msg", 10, 1, 64);
78162306a36Sopenharmony_ci	if (!cert_store_dbf)
78262306a36Sopenharmony_ci		goto cleanup_dbf;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	cert_store_hexdump = debug_register("cert_store_hexdump", 3, 1, 128);
78562306a36Sopenharmony_ci	if (!cert_store_hexdump)
78662306a36Sopenharmony_ci		goto cleanup_dbf;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	debug_register_view(cert_store_hexdump, &debug_hex_ascii_view);
78962306a36Sopenharmony_ci	debug_register_view(cert_store_dbf, &debug_sprintf_view);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* Create directory /sys/firmware/cert_store. */
79262306a36Sopenharmony_ci	cert_store_kobj = kobject_create_and_add("cert_store", firmware_kobj);
79362306a36Sopenharmony_ci	if (!cert_store_kobj)
79462306a36Sopenharmony_ci		goto cleanup_dbf;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	rc = sysfs_create_files(cert_store_kobj, cert_store_attrs);
79762306a36Sopenharmony_ci	if (rc)
79862306a36Sopenharmony_ci		goto cleanup_kobj;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	register_key_type(&key_type_cert_store_key);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return rc;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cicleanup_kobj:
80562306a36Sopenharmony_ci	kobject_put(cert_store_kobj);
80662306a36Sopenharmony_cicleanup_dbf:
80762306a36Sopenharmony_ci	debug_unregister(cert_store_dbf);
80862306a36Sopenharmony_ci	debug_unregister(cert_store_hexdump);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	return rc;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_cidevice_initcall(cert_store_init);
813