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: &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 | return ret; |
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 | return 0; |
95 | } |
96 | |
97 | /* |
98 | * Write the SED Opal key to PLPKS given the label |
99 | */ |
100 | int sed_write_key(char *keyname, char *key, u_int keylen) |
101 | { |
102 | struct plpks_var var; |
103 | struct plpks_sed_object_data data; |
104 | struct plpks_var_name vname; |
105 | |
106 | plpks_init_var(var: &var, keyname); |
107 | |
108 | if (!plpks_sed_available) |
109 | return -EOPNOTSUPP; |
110 | |
111 | var.datalen = sizeof(struct plpks_sed_object_data); |
112 | var.data = (u8 *)&data; |
113 | |
114 | /* initialize SED object */ |
115 | data.version = PLPKS_SED_OBJECT_DATA_V0; |
116 | data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY); |
117 | data.range = cpu_to_be64(PLPKS_SED_RANGE); |
118 | memset(&data.pad1, '\0', sizeof(data.pad1)); |
119 | data.key_len = cpu_to_be32(keylen); |
120 | memcpy(data.key, (char *)key, keylen); |
121 | |
122 | /* |
123 | * Key update requires remove first. The return value |
124 | * is ignored since it's okay if the key doesn't exist. |
125 | */ |
126 | vname.namelen = var.namelen; |
127 | vname.name = var.name; |
128 | plpks_remove_var(var.component, var.os, vname); |
129 | |
130 | return plpks_write_var(var); |
131 | } |
132 | |