secret_common.c (11725B)
1/* 2 * QEMU crypto secret support 3 * 4 * Copyright (c) 2015 Red Hat, Inc. 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 "crypto/secret_common.h" 23#include "crypto/cipher.h" 24#include "qapi/error.h" 25#include "qom/object_interfaces.h" 26#include "qemu/base64.h" 27#include "qemu/module.h" 28#include "trace.h" 29 30 31static void qcrypto_secret_decrypt(QCryptoSecretCommon *secret, 32 const uint8_t *input, 33 size_t inputlen, 34 uint8_t **output, 35 size_t *outputlen, 36 Error **errp) 37{ 38 g_autofree uint8_t *iv = NULL; 39 g_autofree uint8_t *key = NULL; 40 g_autofree uint8_t *ciphertext = NULL; 41 size_t keylen, ciphertextlen, ivlen; 42 g_autoptr(QCryptoCipher) aes = NULL; 43 g_autofree uint8_t *plaintext = NULL; 44 45 *output = NULL; 46 *outputlen = 0; 47 48 if (qcrypto_secret_lookup(secret->keyid, 49 &key, &keylen, 50 errp) < 0) { 51 return; 52 } 53 54 if (keylen != 32) { 55 error_setg(errp, "Key should be 32 bytes in length"); 56 return; 57 } 58 59 if (!secret->iv) { 60 error_setg(errp, "IV is required to decrypt secret"); 61 return; 62 } 63 64 iv = qbase64_decode(secret->iv, -1, &ivlen, errp); 65 if (!iv) { 66 return; 67 } 68 if (ivlen != 16) { 69 error_setg(errp, "IV should be 16 bytes in length not %zu", 70 ivlen); 71 return; 72 } 73 74 aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, 75 QCRYPTO_CIPHER_MODE_CBC, 76 key, keylen, 77 errp); 78 if (!aes) { 79 return; 80 } 81 82 if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { 83 return; 84 } 85 86 if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { 87 ciphertext = qbase64_decode((const gchar *)input, 88 inputlen, 89 &ciphertextlen, 90 errp); 91 if (!ciphertext) { 92 return; 93 } 94 plaintext = g_new0(uint8_t, ciphertextlen + 1); 95 } else { 96 ciphertextlen = inputlen; 97 plaintext = g_new0(uint8_t, inputlen + 1); 98 } 99 if (qcrypto_cipher_decrypt(aes, 100 ciphertext ? ciphertext : input, 101 plaintext, 102 ciphertextlen, 103 errp) < 0) { 104 return; 105 } 106 107 if (plaintext[ciphertextlen - 1] > 16 || 108 plaintext[ciphertextlen - 1] > ciphertextlen) { 109 error_setg(errp, "Incorrect number of padding bytes (%d) " 110 "found on decrypted data", 111 (int)plaintext[ciphertextlen - 1]); 112 return; 113 } 114 115 /* 116 * Even though plaintext may contain arbitrary NUL 117 * ensure it is explicitly NUL terminated. 118 */ 119 ciphertextlen -= plaintext[ciphertextlen - 1]; 120 plaintext[ciphertextlen] = '\0'; 121 122 *output = g_steal_pointer(&plaintext); 123 *outputlen = ciphertextlen; 124} 125 126 127static void qcrypto_secret_decode(const uint8_t *input, 128 size_t inputlen, 129 uint8_t **output, 130 size_t *outputlen, 131 Error **errp) 132{ 133 *output = qbase64_decode((const gchar *)input, 134 inputlen, 135 outputlen, 136 errp); 137} 138 139 140static void 141qcrypto_secret_prop_set_loaded(Object *obj, 142 bool value, 143 Error **errp) 144{ 145 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 146 QCryptoSecretCommonClass *sec_class 147 = QCRYPTO_SECRET_COMMON_GET_CLASS(obj); 148 149 if (value) { 150 Error *local_err = NULL; 151 uint8_t *input = NULL; 152 size_t inputlen = 0; 153 uint8_t *output = NULL; 154 size_t outputlen = 0; 155 156 if (sec_class->load_data) { 157 sec_class->load_data(secret, &input, &inputlen, &local_err); 158 if (local_err) { 159 error_propagate(errp, local_err); 160 return; 161 } 162 } else { 163 error_setg(errp, "%s provides no 'load_data' method'", 164 object_get_typename(obj)); 165 return; 166 } 167 168 if (secret->keyid) { 169 qcrypto_secret_decrypt(secret, input, inputlen, 170 &output, &outputlen, &local_err); 171 g_free(input); 172 if (local_err) { 173 error_propagate(errp, local_err); 174 return; 175 } 176 input = output; 177 inputlen = outputlen; 178 } else { 179 if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { 180 qcrypto_secret_decode(input, inputlen, 181 &output, &outputlen, &local_err); 182 g_free(input); 183 if (local_err) { 184 error_propagate(errp, local_err); 185 return; 186 } 187 input = output; 188 inputlen = outputlen; 189 } 190 } 191 192 secret->rawdata = input; 193 secret->rawlen = inputlen; 194 } else if (secret->rawdata) { 195 error_setg(errp, "Cannot unload secret"); 196 return; 197 } 198} 199 200 201static bool 202qcrypto_secret_prop_get_loaded(Object *obj, 203 Error **errp G_GNUC_UNUSED) 204{ 205 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 206 return secret->rawdata != NULL; 207} 208 209 210static void 211qcrypto_secret_prop_set_format(Object *obj, 212 int value, 213 Error **errp G_GNUC_UNUSED) 214{ 215 QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); 216 creds->format = value; 217} 218 219 220static int 221qcrypto_secret_prop_get_format(Object *obj, 222 Error **errp G_GNUC_UNUSED) 223{ 224 QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj); 225 return creds->format; 226} 227 228 229static void 230qcrypto_secret_prop_set_iv(Object *obj, 231 const char *value, 232 Error **errp) 233{ 234 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 235 236 g_free(secret->iv); 237 secret->iv = g_strdup(value); 238} 239 240 241static char * 242qcrypto_secret_prop_get_iv(Object *obj, 243 Error **errp) 244{ 245 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 246 return g_strdup(secret->iv); 247} 248 249 250static void 251qcrypto_secret_prop_set_keyid(Object *obj, 252 const char *value, 253 Error **errp) 254{ 255 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 256 257 g_free(secret->keyid); 258 secret->keyid = g_strdup(value); 259} 260 261 262static char * 263qcrypto_secret_prop_get_keyid(Object *obj, 264 Error **errp) 265{ 266 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 267 return g_strdup(secret->keyid); 268} 269 270 271static void 272qcrypto_secret_complete(UserCreatable *uc, Error **errp) 273{ 274 object_property_set_bool(OBJECT(uc), "loaded", true, errp); 275} 276 277 278static void 279qcrypto_secret_finalize(Object *obj) 280{ 281 QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj); 282 283 g_free(secret->iv); 284 g_free(secret->keyid); 285 g_free(secret->rawdata); 286} 287 288static void 289qcrypto_secret_class_init(ObjectClass *oc, void *data) 290{ 291 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 292 293 ucc->complete = qcrypto_secret_complete; 294 295 object_class_property_add_bool(oc, "loaded", 296 qcrypto_secret_prop_get_loaded, 297 qcrypto_secret_prop_set_loaded); 298 object_class_property_add_enum(oc, "format", 299 "QCryptoSecretFormat", 300 &QCryptoSecretFormat_lookup, 301 qcrypto_secret_prop_get_format, 302 qcrypto_secret_prop_set_format); 303 object_class_property_add_str(oc, "keyid", 304 qcrypto_secret_prop_get_keyid, 305 qcrypto_secret_prop_set_keyid); 306 object_class_property_add_str(oc, "iv", 307 qcrypto_secret_prop_get_iv, 308 qcrypto_secret_prop_set_iv); 309} 310 311 312int qcrypto_secret_lookup(const char *secretid, 313 uint8_t **data, 314 size_t *datalen, 315 Error **errp) 316{ 317 Object *obj; 318 QCryptoSecretCommon *secret; 319 320 obj = object_resolve_path_component( 321 object_get_objects_root(), secretid); 322 if (!obj) { 323 error_setg(errp, "No secret with id '%s'", secretid); 324 return -1; 325 } 326 327 secret = (QCryptoSecretCommon *) 328 object_dynamic_cast(obj, 329 TYPE_QCRYPTO_SECRET_COMMON); 330 if (!secret) { 331 error_setg(errp, "Object with id '%s' is not a secret", 332 secretid); 333 return -1; 334 } 335 336 if (!secret->rawdata) { 337 error_setg(errp, "Secret with id '%s' has no data", 338 secretid); 339 return -1; 340 } 341 342 *data = g_new0(uint8_t, secret->rawlen + 1); 343 memcpy(*data, secret->rawdata, secret->rawlen); 344 (*data)[secret->rawlen] = '\0'; 345 *datalen = secret->rawlen; 346 347 return 0; 348} 349 350 351char *qcrypto_secret_lookup_as_utf8(const char *secretid, 352 Error **errp) 353{ 354 uint8_t *data; 355 size_t datalen; 356 357 if (qcrypto_secret_lookup(secretid, 358 &data, 359 &datalen, 360 errp) < 0) { 361 return NULL; 362 } 363 364 if (!g_utf8_validate((const gchar *)data, datalen, NULL)) { 365 error_setg(errp, 366 "Data from secret %s is not valid UTF-8", 367 secretid); 368 g_free(data); 369 return NULL; 370 } 371 372 return (char *)data; 373} 374 375 376char *qcrypto_secret_lookup_as_base64(const char *secretid, 377 Error **errp) 378{ 379 uint8_t *data; 380 size_t datalen; 381 char *ret; 382 383 if (qcrypto_secret_lookup(secretid, 384 &data, 385 &datalen, 386 errp) < 0) { 387 return NULL; 388 } 389 390 ret = g_base64_encode(data, datalen); 391 g_free(data); 392 return ret; 393} 394 395 396static const TypeInfo qcrypto_secret_info = { 397 .parent = TYPE_OBJECT, 398 .name = TYPE_QCRYPTO_SECRET_COMMON, 399 .instance_size = sizeof(QCryptoSecretCommon), 400 .instance_finalize = qcrypto_secret_finalize, 401 .class_size = sizeof(QCryptoSecretCommonClass), 402 .class_init = qcrypto_secret_class_init, 403 .abstract = true, 404 .interfaces = (InterfaceInfo[]) { 405 { TYPE_USER_CREATABLE }, 406 { } 407 } 408}; 409 410 411static void 412qcrypto_secret_register_types(void) 413{ 414 type_register_static(&qcrypto_secret_info); 415} 416 417 418type_init(qcrypto_secret_register_types);