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