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 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.h" 23 #include "crypto/cipher.h" 24 #include "qom/object_interfaces.h" 25 #include "qemu/base64.h" 26 #include "trace.h" 27 28 29 static void 30 qcrypto_secret_load_data(QCryptoSecret *secret, 31 uint8_t **output, 32 size_t *outputlen, 33 Error **errp) 34 { 35 char *data = NULL; 36 size_t length = 0; 37 GError *gerr = NULL; 38 39 *output = NULL; 40 *outputlen = 0; 41 42 if (secret->file) { 43 if (secret->data) { 44 error_setg(errp, 45 "'file' and 'data' are mutually exclusive"); 46 return; 47 } 48 if (!g_file_get_contents(secret->file, &data, &length, &gerr)) { 49 error_setg(errp, 50 "Unable to read %s: %s", 51 secret->file, gerr->message); 52 g_error_free(gerr); 53 return; 54 } 55 *output = (uint8_t *)data; 56 *outputlen = length; 57 } else if (secret->data) { 58 *outputlen = strlen(secret->data); 59 *output = (uint8_t *)g_strdup(secret->data); 60 } else { 61 error_setg(errp, "Either 'file' or 'data' must be provided"); 62 } 63 } 64 65 66 static void qcrypto_secret_decrypt(QCryptoSecret *secret, 67 const uint8_t *input, 68 size_t inputlen, 69 uint8_t **output, 70 size_t *outputlen, 71 Error **errp) 72 { 73 uint8_t *key = NULL, *ciphertext = NULL, *iv = NULL; 74 size_t keylen, ciphertextlen, ivlen; 75 QCryptoCipher *aes = NULL; 76 uint8_t *plaintext = NULL; 77 78 *output = NULL; 79 *outputlen = 0; 80 81 if (qcrypto_secret_lookup(secret->keyid, 82 &key, &keylen, 83 errp) < 0) { 84 goto cleanup; 85 } 86 87 if (keylen != 32) { 88 error_setg(errp, "Key should be 32 bytes in length"); 89 goto cleanup; 90 } 91 92 if (!secret->iv) { 93 error_setg(errp, "IV is required to decrypt secret"); 94 goto cleanup; 95 } 96 97 iv = qbase64_decode(secret->iv, -1, &ivlen, errp); 98 if (!iv) { 99 goto cleanup; 100 } 101 if (ivlen != 16) { 102 error_setg(errp, "IV should be 16 bytes in length not %zu", 103 ivlen); 104 goto cleanup; 105 } 106 107 aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256, 108 QCRYPTO_CIPHER_MODE_CBC, 109 key, keylen, 110 errp); 111 if (!aes) { 112 goto cleanup; 113 } 114 115 if (qcrypto_cipher_setiv(aes, iv, ivlen, errp) < 0) { 116 goto cleanup; 117 } 118 119 if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) { 120 ciphertext = qbase64_decode((const gchar*)input, 121 inputlen, 122 &ciphertextlen, 123 errp); 124 if (!ciphertext) { 125 goto cleanup; 126 } 127 plaintext = g_new0(uint8_t, ciphertextlen + 1); 128 } else { 129 ciphertextlen = inputlen; 130 plaintext = g_new0(uint8_t, inputlen + 1); 131 } 132 if (qcrypto_cipher_decrypt(aes, 133 ciphertext ? ciphertext : input, 134 plaintext, 135 ciphertextlen, 136 errp) < 0) { 137 plaintext = NULL; 138 goto cleanup; 139 } 140 141 if (plaintext[ciphertextlen - 1] > 16 || 142 plaintext[ciphertextlen - 1] > ciphertextlen) { 143 error_setg(errp, "Incorrect number of padding bytes (%d) " 144 "found on decrypted data", 145 (int)plaintext[ciphertextlen - 1]); 146 g_free(plaintext); 147 plaintext = NULL; 148 goto cleanup; 149 } 150 151 /* Even though plaintext may contain arbitrary NUL 152 * ensure it is explicitly NUL terminated. 153 */ 154 ciphertextlen -= plaintext[ciphertextlen - 1]; 155 plaintext[ciphertextlen] = '\0'; 156 157 *output = plaintext; 158 *outputlen = ciphertextlen; 159 160 cleanup: 161 g_free(ciphertext); 162 g_free(iv); 163 g_free(key); 164 qcrypto_cipher_free(aes); 165 } 166 167 168 static void qcrypto_secret_decode(const uint8_t *input, 169 size_t inputlen, 170 uint8_t **output, 171 size_t *outputlen, 172 Error **errp) 173 { 174 *output = qbase64_decode((const gchar*)input, 175 inputlen, 176 outputlen, 177 errp); 178 } 179 180 181 static void 182 qcrypto_secret_prop_set_loaded(Object *obj, 183 bool value, 184 Error **errp) 185 { 186 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 187 188 if (value) { 189 Error *local_err = NULL; 190 uint8_t *input = NULL; 191 size_t inputlen = 0; 192 uint8_t *output = NULL; 193 size_t outputlen = 0; 194 195 qcrypto_secret_load_data(secret, &input, &inputlen, &local_err); 196 if (local_err) { 197 error_propagate(errp, local_err); 198 return; 199 } 200 201 if (secret->keyid) { 202 qcrypto_secret_decrypt(secret, input, inputlen, 203 &output, &outputlen, &local_err); 204 g_free(input); 205 if (local_err) { 206 error_propagate(errp, local_err); 207 return; 208 } 209 input = output; 210 inputlen = outputlen; 211 } else { 212 if (secret->format != QCRYPTO_SECRET_FORMAT_RAW) { 213 qcrypto_secret_decode(input, inputlen, 214 &output, &outputlen, &local_err); 215 g_free(input); 216 if (local_err) { 217 error_propagate(errp, local_err); 218 return; 219 } 220 input = output; 221 inputlen = outputlen; 222 } 223 } 224 225 secret->rawdata = input; 226 secret->rawlen = inputlen; 227 } else { 228 g_free(secret->rawdata); 229 secret->rawlen = 0; 230 } 231 } 232 233 234 static bool 235 qcrypto_secret_prop_get_loaded(Object *obj, 236 Error **errp G_GNUC_UNUSED) 237 { 238 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 239 return secret->data != NULL; 240 } 241 242 243 static void 244 qcrypto_secret_prop_set_format(Object *obj, 245 int value, 246 Error **errp G_GNUC_UNUSED) 247 { 248 QCryptoSecret *creds = QCRYPTO_SECRET(obj); 249 250 creds->format = value; 251 } 252 253 254 static int 255 qcrypto_secret_prop_get_format(Object *obj, 256 Error **errp G_GNUC_UNUSED) 257 { 258 QCryptoSecret *creds = QCRYPTO_SECRET(obj); 259 260 return creds->format; 261 } 262 263 264 static void 265 qcrypto_secret_prop_set_data(Object *obj, 266 const char *value, 267 Error **errp) 268 { 269 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 270 271 g_free(secret->data); 272 secret->data = g_strdup(value); 273 } 274 275 276 static char * 277 qcrypto_secret_prop_get_data(Object *obj, 278 Error **errp) 279 { 280 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 281 return g_strdup(secret->data); 282 } 283 284 285 static void 286 qcrypto_secret_prop_set_file(Object *obj, 287 const char *value, 288 Error **errp) 289 { 290 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 291 292 g_free(secret->file); 293 secret->file = g_strdup(value); 294 } 295 296 297 static char * 298 qcrypto_secret_prop_get_file(Object *obj, 299 Error **errp) 300 { 301 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 302 return g_strdup(secret->file); 303 } 304 305 306 static void 307 qcrypto_secret_prop_set_iv(Object *obj, 308 const char *value, 309 Error **errp) 310 { 311 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 312 313 g_free(secret->iv); 314 secret->iv = g_strdup(value); 315 } 316 317 318 static char * 319 qcrypto_secret_prop_get_iv(Object *obj, 320 Error **errp) 321 { 322 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 323 return g_strdup(secret->iv); 324 } 325 326 327 static void 328 qcrypto_secret_prop_set_keyid(Object *obj, 329 const char *value, 330 Error **errp) 331 { 332 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 333 334 g_free(secret->keyid); 335 secret->keyid = g_strdup(value); 336 } 337 338 339 static char * 340 qcrypto_secret_prop_get_keyid(Object *obj, 341 Error **errp) 342 { 343 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 344 return g_strdup(secret->keyid); 345 } 346 347 348 static void 349 qcrypto_secret_complete(UserCreatable *uc, Error **errp) 350 { 351 object_property_set_bool(OBJECT(uc), true, "loaded", errp); 352 } 353 354 355 static void 356 qcrypto_secret_init(Object *obj) 357 { 358 object_property_add_bool(obj, "loaded", 359 qcrypto_secret_prop_get_loaded, 360 qcrypto_secret_prop_set_loaded, 361 NULL); 362 object_property_add_enum(obj, "format", 363 "QCryptoSecretFormat", 364 QCryptoSecretFormat_lookup, 365 qcrypto_secret_prop_get_format, 366 qcrypto_secret_prop_set_format, 367 NULL); 368 object_property_add_str(obj, "data", 369 qcrypto_secret_prop_get_data, 370 qcrypto_secret_prop_set_data, 371 NULL); 372 object_property_add_str(obj, "file", 373 qcrypto_secret_prop_get_file, 374 qcrypto_secret_prop_set_file, 375 NULL); 376 object_property_add_str(obj, "keyid", 377 qcrypto_secret_prop_get_keyid, 378 qcrypto_secret_prop_set_keyid, 379 NULL); 380 object_property_add_str(obj, "iv", 381 qcrypto_secret_prop_get_iv, 382 qcrypto_secret_prop_set_iv, 383 NULL); 384 } 385 386 387 static void 388 qcrypto_secret_finalize(Object *obj) 389 { 390 QCryptoSecret *secret = QCRYPTO_SECRET(obj); 391 392 g_free(secret->iv); 393 g_free(secret->file); 394 g_free(secret->keyid); 395 g_free(secret->rawdata); 396 g_free(secret->data); 397 } 398 399 static void 400 qcrypto_secret_class_init(ObjectClass *oc, void *data) 401 { 402 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 403 404 ucc->complete = qcrypto_secret_complete; 405 } 406 407 408 int qcrypto_secret_lookup(const char *secretid, 409 uint8_t **data, 410 size_t *datalen, 411 Error **errp) 412 { 413 Object *obj; 414 QCryptoSecret *secret; 415 416 obj = object_resolve_path_component( 417 object_get_objects_root(), secretid); 418 if (!obj) { 419 error_setg(errp, "No secret with id '%s'", secretid); 420 return -1; 421 } 422 423 secret = (QCryptoSecret *) 424 object_dynamic_cast(obj, 425 TYPE_QCRYPTO_SECRET); 426 if (!secret) { 427 error_setg(errp, "Object with id '%s' is not a secret", 428 secretid); 429 return -1; 430 } 431 432 if (!secret->rawdata) { 433 error_setg(errp, "Secret with id '%s' has no data", 434 secretid); 435 return -1; 436 } 437 438 *data = g_new0(uint8_t, secret->rawlen + 1); 439 memcpy(*data, secret->rawdata, secret->rawlen); 440 (*data)[secret->rawlen] = '\0'; 441 *datalen = secret->rawlen; 442 443 return 0; 444 } 445 446 447 char *qcrypto_secret_lookup_as_utf8(const char *secretid, 448 Error **errp) 449 { 450 uint8_t *data; 451 size_t datalen; 452 453 if (qcrypto_secret_lookup(secretid, 454 &data, 455 &datalen, 456 errp) < 0) { 457 return NULL; 458 } 459 460 if (!g_utf8_validate((const gchar*)data, datalen, NULL)) { 461 error_setg(errp, 462 "Data from secret %s is not valid UTF-8", 463 secretid); 464 g_free(data); 465 return NULL; 466 } 467 468 return (char *)data; 469 } 470 471 472 char *qcrypto_secret_lookup_as_base64(const char *secretid, 473 Error **errp) 474 { 475 uint8_t *data; 476 size_t datalen; 477 char *ret; 478 479 if (qcrypto_secret_lookup(secretid, 480 &data, 481 &datalen, 482 errp) < 0) { 483 return NULL; 484 } 485 486 ret = g_base64_encode(data, datalen); 487 g_free(data); 488 return ret; 489 } 490 491 492 static const TypeInfo qcrypto_secret_info = { 493 .parent = TYPE_OBJECT, 494 .name = TYPE_QCRYPTO_SECRET, 495 .instance_size = sizeof(QCryptoSecret), 496 .instance_init = qcrypto_secret_init, 497 .instance_finalize = qcrypto_secret_finalize, 498 .class_size = sizeof(QCryptoSecretClass), 499 .class_init = qcrypto_secret_class_init, 500 .interfaces = (InterfaceInfo[]) { 501 { TYPE_USER_CREATABLE }, 502 { } 503 } 504 }; 505 506 507 static void 508 qcrypto_secret_register_types(void) 509 { 510 type_register_static(&qcrypto_secret_info); 511 } 512 513 514 type_init(qcrypto_secret_register_types); 515