1 /* 2 * QEMU crypto secret support 3 * 4 * Copyright 2020 Yandex N.V. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include <asm/unistd.h> 23 #include <linux/keyctl.h> 24 #include "qapi/error.h" 25 #include "qom/object_interfaces.h" 26 #include "trace.h" 27 #include "crypto/secret_keyring.h" 28 29 30 static inline 31 long keyctl_read(int32_t key, uint8_t *buffer, size_t buflen) 32 { 33 return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen, 0); 34 } 35 36 37 static void 38 qcrypto_secret_keyring_load_data(QCryptoSecretCommon *sec_common, 39 uint8_t **output, 40 size_t *outputlen, 41 Error **errp) 42 { 43 QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(sec_common); 44 uint8_t *buffer = NULL; 45 long retcode; 46 47 *output = NULL; 48 *outputlen = 0; 49 50 if (!secret->serial) { 51 error_setg(errp, "'serial' parameter must be provided"); 52 return; 53 } 54 55 retcode = keyctl_read(secret->serial, NULL, 0); 56 if (retcode <= 0) { 57 goto keyctl_error; 58 } 59 60 buffer = g_new0(uint8_t, retcode); 61 62 retcode = keyctl_read(secret->serial, buffer, retcode); 63 if (retcode < 0) { 64 g_free(buffer); 65 goto keyctl_error; 66 } 67 68 *outputlen = retcode; 69 *output = buffer; 70 return; 71 72 keyctl_error: 73 error_setg_errno(errp, errno, 74 "Unable to read serial key %08x", 75 secret->serial); 76 } 77 78 79 static void 80 qcrypto_secret_prop_set_key(Object *obj, Visitor *v, 81 const char *name, void *opaque, 82 Error **errp) 83 { 84 QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); 85 int32_t value; 86 visit_type_int32(v, name, &value, errp); 87 if (!value) { 88 error_setg(errp, "'serial' should not be equal to 0"); 89 } 90 secret->serial = value; 91 } 92 93 94 static void 95 qcrypto_secret_prop_get_key(Object *obj, Visitor *v, 96 const char *name, void *opaque, 97 Error **errp) 98 { 99 QCryptoSecretKeyring *secret = QCRYPTO_SECRET_KEYRING(obj); 100 int32_t value = secret->serial; 101 visit_type_int32(v, name, &value, errp); 102 } 103 104 105 static void 106 qcrypto_secret_keyring_complete(UserCreatable *uc, Error **errp) 107 { 108 object_property_set_bool(OBJECT(uc), "loaded", true, errp); 109 } 110 111 112 static void 113 qcrypto_secret_keyring_class_init(ObjectClass *oc, void *data) 114 { 115 QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); 116 sic->load_data = qcrypto_secret_keyring_load_data; 117 118 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 119 ucc->complete = qcrypto_secret_keyring_complete; 120 121 object_class_property_add(oc, "serial", "int32_t", 122 qcrypto_secret_prop_get_key, 123 qcrypto_secret_prop_set_key, 124 NULL, NULL); 125 } 126 127 128 static const TypeInfo qcrypto_secret_info = { 129 .parent = TYPE_QCRYPTO_SECRET_COMMON, 130 .name = TYPE_QCRYPTO_SECRET_KEYRING, 131 .instance_size = sizeof(QCryptoSecretKeyring), 132 .class_size = sizeof(QCryptoSecretKeyringClass), 133 .class_init = qcrypto_secret_keyring_class_init, 134 .interfaces = (InterfaceInfo[]) { 135 { TYPE_USER_CREATABLE }, 136 { } 137 } 138 }; 139 140 141 static void 142 qcrypto_secret_register_types(void) 143 { 144 type_register_static(&qcrypto_secret_info); 145 } 146 147 148 type_init(qcrypto_secret_register_types); 149