qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

secret_common.c (11203B)


      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 
     31 static 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 
    127 static 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 
    140 static void
    141 qcrypto_secret_complete(UserCreatable *uc, Error **errp)
    142 {
    143     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(uc);
    144     QCryptoSecretCommonClass *sec_class
    145                                 = QCRYPTO_SECRET_COMMON_GET_CLASS(uc);
    146 
    147     Error *local_err = NULL;
    148     uint8_t *input = NULL;
    149     size_t inputlen = 0;
    150     uint8_t *output = NULL;
    151     size_t outputlen = 0;
    152 
    153     if (sec_class->load_data) {
    154         sec_class->load_data(secret, &input, &inputlen, &local_err);
    155         if (local_err) {
    156             error_propagate(errp, local_err);
    157             return;
    158         }
    159     } else {
    160         error_setg(errp, "%s provides no 'load_data' method'",
    161                          object_get_typename(OBJECT(uc)));
    162         return;
    163     }
    164 
    165     if (secret->keyid) {
    166         qcrypto_secret_decrypt(secret, input, inputlen,
    167                                &output, &outputlen, &local_err);
    168         g_free(input);
    169         if (local_err) {
    170             error_propagate(errp, local_err);
    171             return;
    172         }
    173         input = output;
    174         inputlen = outputlen;
    175     } else {
    176         if (secret->format == QCRYPTO_SECRET_FORMAT_BASE64) {
    177             qcrypto_secret_decode(input, inputlen,
    178                                   &output, &outputlen, &local_err);
    179             g_free(input);
    180             if (local_err) {
    181                 error_propagate(errp, local_err);
    182                 return;
    183             }
    184             input = output;
    185             inputlen = outputlen;
    186         }
    187     }
    188 
    189     secret->rawdata = input;
    190     secret->rawlen = inputlen;
    191 }
    192 
    193 
    194 static bool
    195 qcrypto_secret_prop_get_loaded(Object *obj,
    196                                Error **errp G_GNUC_UNUSED)
    197 {
    198     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    199     return secret->rawdata != NULL;
    200 }
    201 
    202 
    203 static void
    204 qcrypto_secret_prop_set_format(Object *obj,
    205                                int value,
    206                                Error **errp G_GNUC_UNUSED)
    207 {
    208     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
    209     creds->format = value;
    210 }
    211 
    212 
    213 static int
    214 qcrypto_secret_prop_get_format(Object *obj,
    215                                Error **errp G_GNUC_UNUSED)
    216 {
    217     QCryptoSecretCommon *creds = QCRYPTO_SECRET_COMMON(obj);
    218     return creds->format;
    219 }
    220 
    221 
    222 static void
    223 qcrypto_secret_prop_set_iv(Object *obj,
    224                            const char *value,
    225                            Error **errp)
    226 {
    227     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    228 
    229     g_free(secret->iv);
    230     secret->iv = g_strdup(value);
    231 }
    232 
    233 
    234 static char *
    235 qcrypto_secret_prop_get_iv(Object *obj,
    236                            Error **errp)
    237 {
    238     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    239     return g_strdup(secret->iv);
    240 }
    241 
    242 
    243 static void
    244 qcrypto_secret_prop_set_keyid(Object *obj,
    245                               const char *value,
    246                               Error **errp)
    247 {
    248     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    249 
    250     g_free(secret->keyid);
    251     secret->keyid = g_strdup(value);
    252 }
    253 
    254 
    255 static char *
    256 qcrypto_secret_prop_get_keyid(Object *obj,
    257                               Error **errp)
    258 {
    259     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    260     return g_strdup(secret->keyid);
    261 }
    262 
    263 
    264 static void
    265 qcrypto_secret_finalize(Object *obj)
    266 {
    267     QCryptoSecretCommon *secret = QCRYPTO_SECRET_COMMON(obj);
    268 
    269     g_free(secret->iv);
    270     g_free(secret->keyid);
    271     g_free(secret->rawdata);
    272 }
    273 
    274 static void
    275 qcrypto_secret_class_init(ObjectClass *oc, void *data)
    276 {
    277     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
    278 
    279     ucc->complete = qcrypto_secret_complete;
    280 
    281     object_class_property_add_bool(oc, "loaded",
    282                                    qcrypto_secret_prop_get_loaded,
    283                                    NULL);
    284     object_class_property_add_enum(oc, "format",
    285                                    "QCryptoSecretFormat",
    286                                    &QCryptoSecretFormat_lookup,
    287                                    qcrypto_secret_prop_get_format,
    288                                    qcrypto_secret_prop_set_format);
    289     object_class_property_add_str(oc, "keyid",
    290                                   qcrypto_secret_prop_get_keyid,
    291                                   qcrypto_secret_prop_set_keyid);
    292     object_class_property_add_str(oc, "iv",
    293                                   qcrypto_secret_prop_get_iv,
    294                                   qcrypto_secret_prop_set_iv);
    295 }
    296 
    297 
    298 int qcrypto_secret_lookup(const char *secretid,
    299                           uint8_t **data,
    300                           size_t *datalen,
    301                           Error **errp)
    302 {
    303     Object *obj;
    304     QCryptoSecretCommon *secret;
    305 
    306     obj = object_resolve_path_component(
    307         object_get_objects_root(), secretid);
    308     if (!obj) {
    309         error_setg(errp, "No secret with id '%s'", secretid);
    310         return -1;
    311     }
    312 
    313     secret = (QCryptoSecretCommon *)
    314         object_dynamic_cast(obj,
    315                             TYPE_QCRYPTO_SECRET_COMMON);
    316     if (!secret) {
    317         error_setg(errp, "Object with id '%s' is not a secret",
    318                    secretid);
    319         return -1;
    320     }
    321 
    322     if (!secret->rawdata) {
    323         error_setg(errp, "Secret with id '%s' has no data",
    324                    secretid);
    325         return -1;
    326     }
    327 
    328     *data = g_new0(uint8_t, secret->rawlen + 1);
    329     memcpy(*data, secret->rawdata, secret->rawlen);
    330     (*data)[secret->rawlen] = '\0';
    331     *datalen = secret->rawlen;
    332 
    333     return 0;
    334 }
    335 
    336 
    337 char *qcrypto_secret_lookup_as_utf8(const char *secretid,
    338                                     Error **errp)
    339 {
    340     uint8_t *data;
    341     size_t datalen;
    342 
    343     if (qcrypto_secret_lookup(secretid,
    344                               &data,
    345                               &datalen,
    346                               errp) < 0) {
    347         return NULL;
    348     }
    349 
    350     if (!g_utf8_validate((const gchar *)data, datalen, NULL)) {
    351         error_setg(errp,
    352                    "Data from secret %s is not valid UTF-8",
    353                    secretid);
    354         g_free(data);
    355         return NULL;
    356     }
    357 
    358     return (char *)data;
    359 }
    360 
    361 
    362 char *qcrypto_secret_lookup_as_base64(const char *secretid,
    363                                       Error **errp)
    364 {
    365     uint8_t *data;
    366     size_t datalen;
    367     char *ret;
    368 
    369     if (qcrypto_secret_lookup(secretid,
    370                               &data,
    371                               &datalen,
    372                               errp) < 0) {
    373         return NULL;
    374     }
    375 
    376     ret = g_base64_encode(data, datalen);
    377     g_free(data);
    378     return ret;
    379 }
    380 
    381 
    382 static const TypeInfo qcrypto_secret_info = {
    383     .parent = TYPE_OBJECT,
    384     .name = TYPE_QCRYPTO_SECRET_COMMON,
    385     .instance_size = sizeof(QCryptoSecretCommon),
    386     .instance_finalize = qcrypto_secret_finalize,
    387     .class_size = sizeof(QCryptoSecretCommonClass),
    388     .class_init = qcrypto_secret_class_init,
    389     .abstract = true,
    390     .interfaces = (InterfaceInfo[]) {
    391         { TYPE_USER_CREATABLE },
    392         { }
    393     }
    394 };
    395 
    396 
    397 static void
    398 qcrypto_secret_register_types(void)
    399 {
    400     type_register_static(&qcrypto_secret_info);
    401 }
    402 
    403 
    404 type_init(qcrypto_secret_register_types);