xref: /linux/arch/powerpc/platforms/pseries/plpks_sed_ops.c (revision 217ba01e5b9096091acc2c1a3776cb3eb88c00ff)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * POWER Platform specific code for non-volatile SED key access
4  * Copyright (C) 2022 IBM Corporation
5  *
6  * Define operations for SED Opal to read/write keys
7  * from POWER LPAR Platform KeyStore(PLPKS).
8  *
9  * Self Encrypting Drives(SED) key storage using PLPKS
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
14 #include <linux/string.h>
15 #include <linux/ioctl.h>
16 #include <linux/sed-opal-key.h>
17 #include <asm/plpks.h>
18 
19 static bool plpks_sed_initialized = false;
20 static bool plpks_sed_available = false;
21 
22 /*
23  * structure that contains all SED data
24  */
25 struct plpks_sed_object_data {
26 	u_char version;
27 	u_char pad1[7];
28 	u_long authority;
29 	u_long range;
30 	u_int  key_len;
31 	u_char key[32];
32 };
33 
34 #define PLPKS_SED_OBJECT_DATA_V0        0
35 #define PLPKS_SED_MANGLED_LABEL         "/default/pri"
36 #define PLPKS_SED_COMPONENT             "sed-opal"
37 #define PLPKS_SED_KEY                   "opal-boot-pin"
38 
39 /*
40  * authority is admin1 and range is global
41  */
42 #define PLPKS_SED_AUTHORITY  0x0000000900010001
43 #define PLPKS_SED_RANGE      0x0000080200000001
44 
45 static void plpks_init_var(struct plpks_var *var, char *keyname)
46 {
47 	if (!plpks_sed_initialized) {
48 		plpks_sed_initialized = true;
49 		plpks_sed_available = plpks_is_available();
50 		if (!plpks_sed_available)
51 			pr_err("SED: plpks not available\n");
52 	}
53 
54 	var->name = keyname;
55 	var->namelen = strlen(keyname);
56 	if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
57 		var->name = PLPKS_SED_MANGLED_LABEL;
58 		var->namelen = strlen(keyname);
59 	}
60 	var->policy = PLPKS_WORLDREADABLE;
61 	var->os = PLPKS_VAR_COMMON;
62 	var->data = NULL;
63 	var->datalen = 0;
64 	var->component = PLPKS_SED_COMPONENT;
65 }
66 
67 /*
68  * Read the SED Opal key from PLPKS given the label
69  */
70 int sed_read_key(char *keyname, char *key, u_int *keylen)
71 {
72 	struct plpks_var var;
73 	struct plpks_sed_object_data data;
74 	int ret;
75 	u_int len;
76 
77 	plpks_init_var(&var, keyname);
78 
79 	if (!plpks_sed_available)
80 		return -EOPNOTSUPP;
81 
82 	var.data = (u8 *)&data;
83 	var.datalen = sizeof(data);
84 
85 	ret = plpks_read_os_var(&var);
86 	if (ret != 0)
87 		goto out;
88 
89 	len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
90 	memcpy(key, data.key, len);
91 	key[len] = '\0';
92 	*keylen = len;
93 
94 out:
95 	memzero_explicit(&data, sizeof(data));
96 	return ret;
97 }
98 
99 /*
100  * Write the SED Opal key to PLPKS given the label
101  */
102 int sed_write_key(char *keyname, char *key, u_int keylen)
103 {
104 	struct plpks_var var;
105 	struct plpks_sed_object_data data;
106 	struct plpks_var_name vname;
107 	int ret;
108 
109 	plpks_init_var(&var, keyname);
110 
111 	if (!plpks_sed_available)
112 		return -EOPNOTSUPP;
113 
114 	var.datalen = sizeof(struct plpks_sed_object_data);
115 	var.data = (u8 *)&data;
116 
117 	/* initialize SED object */
118 	data.version = PLPKS_SED_OBJECT_DATA_V0;
119 	data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
120 	data.range = cpu_to_be64(PLPKS_SED_RANGE);
121 	memset(&data.pad1, '\0', sizeof(data.pad1));
122 	data.key_len = cpu_to_be32(keylen);
123 	memcpy(data.key, (char *)key, keylen);
124 
125 	/*
126 	 * Key update requires remove first. The return value
127 	 * is ignored since it's okay if the key doesn't exist.
128 	 */
129 	vname.namelen = var.namelen;
130 	vname.name = var.name;
131 	plpks_remove_var(var.component, var.os, vname);
132 
133 	ret = plpks_write_var(var);
134 	memzero_explicit(&data, sizeof(data));
135 
136 	return ret;
137 }
138