cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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);