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