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 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, 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.