qemu/hw/misc/xlnx-aes.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the Xilinx AES
   3 *
   4 * Copyright (c) 2018 Xilinx Inc.
   5 *
   6 * Written by Edgar E. Iglesias <edgari@xilinx.com>
   7 *            Sai Pavan Boddu <saipava@xilinx.com>
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "qemu/log.h"
  30#include "qemu/error-report.h"
  31#include "qapi/error.h"
  32#include "hw/misc/xlnx-aes.h"
  33#include "migration/vmstate.h"
  34#include "hw/qdev-properties.h"
  35
  36#include "hw/fdt_generic_util.h"
  37
  38#ifndef XLNX_AES_ERR_DEBUG
  39#define XLNX_AES_ERR_DEBUG 0
  40#endif
  41
  42#define XLNX_AES(obj) \
  43     OBJECT_CHECK(XlnxAES, (obj), TYPE_XLNX_AES)
  44
  45#define DPRINT(fmt, args...) do { \
  46        if (XLNX_AES_ERR_DEBUG) { \
  47            qemu_log("%s:" fmt, __func__, ##args);\
  48        } \
  49    } while (0)
  50
  51/* Debug print without function-name prefix */
  52#define DPRINT_NP(fmt, args...) do { \
  53        if (XLNX_AES_ERR_DEBUG) { \
  54            qemu_log(fmt, ##args); \
  55        } \
  56    } while (0)
  57
  58#define XLNX_AES_PACKED_LEN  sizeof(((XlnxAES *)0)->pack_buf.u8)
  59
  60/* This implements a model of the Xlnx AES unit.  */
  61static const char *aes_state2str(enum XlnxAESState state)
  62{
  63    static const char *state2str[] = {
  64        [IDLE] = "IDLE",
  65        [IV] = "IV",
  66        [AAD] = "AAD",
  67        [PAYLOAD] = "PAYLOAD",
  68        [TAG0] = "TAG0",
  69        [TAG1] = "TAG1",
  70        [TAG2] = "TAG2",
  71        [TAG3] = "TAG3",
  72    };
  73    return state2str[state];
  74}
  75
  76static int xlnx_check_state(XlnxAES *s,
  77                              enum XlnxAESState expected,
  78                              const char *descr)
  79{
  80    int err = 0;
  81    if (s->state != expected) {
  82        qemu_log_mask(LOG_GUEST_ERROR,
  83                  "%s: %s, while state is %s (expected %s)\n",
  84                  s->prefix, descr,
  85                  aes_state2str(s->state), aes_state2str(expected));
  86        err = 1;
  87    }
  88    return err;
  89}
  90
  91static void xlnx_aes_set_state(XlnxAES *s, enum XlnxAESState state)
  92{
  93    assert(state <= TAG3);
  94    s->state = state;
  95
  96    if (s->state != IDLE) {
  97        s->inp_ready = 1;
  98    } else {
  99        s->inp_ready = 0;
 100    }
 101
 102    if (state == AAD) {
 103        s->aad_ready = true;
 104    }
 105}
 106
 107void xlnx_aes_write_key(XlnxAES *s, unsigned int pos, uint32_t val)
 108{
 109    if (xlnx_check_state(s, IDLE, "Loading key")) {
 110        return;
 111    }
 112
 113    assert(pos < 8);
 114    /* Xlnx wants the key in big-endian.  */
 115    s->key[pos] = bswap32(val);
 116}
 117
 118void xlnx_aes_load_key(XlnxAES *s, int len)
 119{
 120    int i;
 121
 122    if (xlnx_check_state(s, IDLE, "Loading key")) {
 123        return;
 124    }
 125
 126    DPRINT("AES KEY loaded (big endian):\n");
 127    for (i = 0; i < len / 32; i++) {
 128        DPRINT_NP("0x%08x ", s->key[i]);
 129    }
 130    DPRINT_NP("\n");
 131
 132    s->keylen = len;
 133    s->key_zeroed = 0;
 134}
 135
 136void xlnx_aes_key_zero(XlnxAES *s)
 137{
 138    if (xlnx_check_state(s, IDLE, "Clearing key")) {
 139        return;
 140    }
 141    memset(s->key, 0, sizeof s->key);
 142    s->key_zeroed = 1;
 143}
 144
 145static void xlnx_aes_load_iv(XlnxAES *s)
 146{
 147    if (s->state == IV) {
 148        unsigned int keylen = s->keylen;
 149        int r, i;
 150
 151        if (keylen == 0) {
 152            qemu_log_mask(LOG_GUEST_ERROR, "CSU-AES: Data but no key!\n");
 153            /* Use zero key.  */
 154            memset(s->key, 0, sizeof s->key);
 155            keylen = 256;
 156        }
 157        r = gcm_init(&s->gcm_ctx, (void *) s->key, keylen);
 158        if (r != 0) {
 159            qemu_log_mask(LOG_GUEST_ERROR, "CSU-AES: GCM init failed\n");
 160            return;
 161        }
 162        gcm_push_iv(&s->gcm_ctx, (void *) s->iv, 12, 16);
 163        DPRINT("IV (big endian):\n");
 164        for (i = 0; i < 4; i++) {
 165            DPRINT_NP("0x%08x ", s->iv[i]);
 166        }
 167        DPRINT_NP("\n");
 168    }
 169}
 170
 171static bool xlnx_aes_pack_empty(XlnxAES *s)
 172{
 173    return s->pack_next == 0;
 174}
 175
 176static bool xlnx_aes_pack_full(XlnxAES *s)
 177{
 178    return s->pack_next >= XLNX_AES_PACKED_LEN;
 179}
 180
 181static bool xlnx_aes_pack_pad0(XlnxAES *s)
 182{
 183    /* Pad the packing buffer only if not empty and not full */
 184    int pad = XLNX_AES_PACKED_LEN - s->pack_next;
 185
 186    if (pad > 0 && pad < XLNX_AES_PACKED_LEN) {
 187        memset(&s->pack_buf.u8[s->pack_next], 0, pad);
 188        s->pack_next = XLNX_AES_PACKED_LEN;
 189
 190        return true;
 191    } else {
 192        return xlnx_aes_pack_full(s);
 193    }
 194}
 195
 196static unsigned int xlnx_aes_pack_push(XlnxAES *s, const void *data,
 197                                       unsigned len, bool last_word)
 198{
 199    unsigned next, plen;
 200
 201    assert(s->state != PAYLOAD); /* PAYLOAD not subject to packing */
 202
 203    if (!len) {
 204        return 0;
 205    }
 206
 207    next = s->pack_next;
 208    assert(next < XLNX_AES_PACKED_LEN);
 209
 210    plen = MIN(len, XLNX_AES_PACKED_LEN - next);
 211
 212    memcpy(&s->pack_buf.u8[next], data, plen);
 213    s->pack_next = next + plen;
 214
 215    /*
 216     * Trigger padding if having packed end-of-message byte.
 217     * 1/ To pad shortened IV
 218     * 2/ To pad shortened TAG (on decrypt)
 219     * 3/ To pad AAD (on encrypt) to multiple of block-size (16 bytes)
 220     */
 221    if (plen == len && last_word) {
 222        xlnx_aes_pack_pad0(s);
 223    }
 224
 225    return plen;
 226}
 227
 228static unsigned xlnx_aes_load_aad(XlnxAES *s, const void *data, unsigned len)
 229{
 230    assert(s->aad_ready);
 231
 232    /* Auto-reset packing if sourced from packer */
 233    if ((const void *)&s->pack_buf == data) {
 234        len = s->pack_next;
 235        s->pack_next = 0;
 236    }
 237
 238    /* An empty or partial block stops aad */
 239    if (!len) {
 240        s->aad_ready = false;
 241        return 0;
 242    }
 243
 244    if (len & 15) {
 245        s->aad_ready = false;
 246    }
 247
 248    gcm_push_aad(&s->gcm_ctx, data, len);
 249    return len;
 250}
 251
 252static unsigned xlnx_aes_push_aad(XlnxAES *s, const uint8_t *data,
 253                                  const unsigned len, bool is_aad, void *outbuf)
 254{
 255    unsigned pos = 0, blen;
 256
 257    assert(!xlnx_check_state(s, AAD, "Loading AAD"));
 258
 259    if (!is_aad) {
 260        /*
 261         * data is actual payload. Thus, AAD phase has ended,
 262         * and residual AAD from earlier push(es) must be flused.
 263         */
 264        xlnx_aes_load_aad(s, &s->pack_buf, 0);
 265
 266        /* None consumed; pass all given data to PAYLOAD state */
 267        xlnx_aes_set_state(s, PAYLOAD);
 268        return 0;
 269    }
 270
 271    /* The entire AAD goes straight through.  */
 272    memcpy(outbuf, data, len);
 273
 274    if (!xlnx_aes_pack_empty(s)) {
 275        /* Combine with AAD from earlier pushes into a block */
 276        pos = xlnx_aes_pack_push(s, data, len, false);
 277
 278        /* A partially packed buffer is not ready to be loaded yet */
 279        if (!xlnx_aes_pack_full(s)) {
 280            assert(pos == len);
 281            return len;
 282        }
 283
 284        xlnx_aes_load_aad(s, &s->pack_buf, 0);
 285        assert(xlnx_aes_pack_empty(s));
 286    }
 287
 288    /* Sink more AAD by the blocks */
 289    blen = QEMU_ALIGN_DOWN(len, XLNX_AES_PACKED_LEN);
 290    if (blen) {
 291        pos += xlnx_aes_load_aad(s, &data[pos], blen);
 292    }
 293
 294    /* Collect AAD tail into the empty packing buffer */
 295    pos += xlnx_aes_pack_push(s, &data[pos], (len - pos), false);
 296
 297    /* All data should have been consumed */
 298    assert(pos == len);
 299    return len;
 300}
 301
 302static unsigned xlnx_aes_push_iv(XlnxAES *s, const void *data,
 303                                 unsigned len, bool last_word)
 304{
 305    int pos;
 306
 307    assert(!xlnx_check_state(s, IV, "Loading IV"));
 308
 309    /* Collect 16 bytes as IV */
 310    pos = xlnx_aes_pack_push(s, data, len, last_word);
 311
 312    if (xlnx_aes_pack_full(s)) {
 313        memcpy(s->iv, &s->pack_buf, sizeof(s->iv));
 314        s->pack_next = 0;
 315
 316        xlnx_aes_load_iv(s);
 317        xlnx_aes_set_state(s, AAD);
 318    }
 319
 320    return pos;
 321}
 322
 323void xlnx_aes_start_message(XlnxAES *s, bool encrypt)
 324{
 325    if (xlnx_check_state(s, IDLE, "Start message")) {
 326        /* Clean up then proceed anyway */
 327        xlnx_aes_set_state(s, IDLE);
 328        qemu_set_irq(s->s_busy, false);
 329    }
 330    /* Loading IV.  */
 331    xlnx_aes_set_state(s, IV);
 332    s->pack_next = 0;
 333    s->encrypt = encrypt;
 334    s->tag_ok = 0;
 335
 336    qemu_set_irq(s->s_done, false);
 337    qemu_set_irq(s->s_busy, false);
 338}
 339
 340static void xlnx_aes_done(XlnxAES *s)
 341{
 342    xlnx_aes_set_state(s, IDLE);
 343    qemu_set_irq(s->s_done, true);
 344    qemu_set_irq(s->s_busy, false);
 345}
 346
 347/* Length is in bytes.  */
 348int xlnx_aes_push_data(XlnxAES *s,
 349                       const uint8_t *data8, unsigned len,
 350                       bool is_aad, bool last_word, int lw_len,
 351                       uint8_t *outbuf, int *outlen)
 352{
 353    unsigned pos = 0, opos = 0, plen;
 354    uint32_t v32;
 355
 356    assert(!last_word || lw_len == 0 || lw_len == 4);
 357    qemu_set_irq(s->s_busy, true);
 358
 359    while (pos < len) {
 360        plen = len - pos;
 361        switch (s->state) {
 362        case IDLE:
 363            qemu_log_mask(LOG_GUEST_ERROR, "AES: Data while idle\n");
 364            return len;
 365        case IV:
 366            pos += xlnx_aes_push_iv(s, &data8[pos], plen, last_word);
 367            break;
 368        case AAD:
 369            plen = xlnx_aes_push_aad(s, &data8[pos], plen, is_aad,
 370                                     outbuf + opos);
 371            pos += plen;
 372            opos += plen;
 373            break;
 374        case PAYLOAD:
 375            gcm_push_data(&s->gcm_ctx, s->encrypt ? AES_ENCRYPT : AES_DECRYPT,
 376                          outbuf + opos, &data8[pos], plen);
 377            pos += plen;
 378            opos += plen;
 379            break;
 380        case TAG0...TAG3:
 381            /* Only decrypt case has data here.  */
 382            assert(s->encrypt == 0);
 383            assert(len >= 4);
 384
 385            memcpy(&v32, data8 + pos, 4);
 386            s->tag[s->state - TAG0] = v32;
 387            pos += 4;
 388            if (s->state == TAG3) {
 389                uint8_t tag[16];
 390
 391                gcm_emit_tag(&s->gcm_ctx, tag, 16);
 392                s->tag_ok = memcmp(s->tag, tag, 16) == 0;
 393                if (XLNX_AES_ERR_DEBUG) {
 394                    qemu_hexdump(stderr, "expected-tag",
 395                                 (void *) s->tag, 16);
 396                    qemu_hexdump(stderr, "tag", (void *) tag, 16);
 397                }
 398                xlnx_aes_done(s);
 399                goto done;
 400            }
 401            xlnx_aes_set_state(s, s->state + 1);
 402            break;
 403        default:
 404            assert(0);
 405            break;
 406        }
 407    }
 408
 409    /* 'last_word' is honored only for PAYLOAD phase */
 410    if (last_word && s->state == PAYLOAD) {
 411        if (s->encrypt) {
 412            /* Emit tag on end-of-message */
 413            gcm_emit_tag(&s->gcm_ctx, outbuf + opos, 16);
 414            opos += 16;
 415            xlnx_aes_done(s);
 416        } else {
 417            /* Receive 16-byte TAG to compare with calculated */
 418            xlnx_aes_set_state(s, TAG0);
 419            qemu_set_irq(s->s_busy, false);
 420        }
 421    }
 422
 423done:
 424    if (outlen) {
 425        *outlen = opos;
 426    }
 427    return pos;
 428}
 429
 430static void xlnx_aes_reset(DeviceState *dev)
 431{
 432    XlnxAES *s =  XLNX_AES(dev);
 433
 434    s->state = IDLE;
 435    s->encrypt = false;
 436    s->tag_ok = false;
 437    s->key_zeroed = false;
 438    s->inp_ready = false;
 439    memset(s->iv, 0, 16);
 440    memset(s->tag, 0, 16);
 441    memset(s->key, 0, 32);
 442    s->keylen = 256;
 443
 444    qemu_set_irq(s->s_done, false);
 445    qemu_set_irq(s->s_busy, false);
 446}
 447
 448static void reset_handler(void *opaque, int n, int level)
 449{
 450    XlnxAES *s = XLNX_AES(opaque);
 451
 452    if (level) {
 453        xlnx_aes_reset(DEVICE(s));
 454    }
 455}
 456
 457static void xlnx_aes_realize(DeviceState *dev, Error **errp)
 458{
 459    XlnxAES *s =  XLNX_AES(dev);
 460
 461    qdev_init_gpio_out(dev, &s->s_busy, 1);
 462    qdev_init_gpio_out(dev, &s->s_done, 1);
 463    qdev_init_gpio_in_named(dev, reset_handler, "reset", 1);
 464}
 465
 466static void xlnx_aes_class_init(ObjectClass *klass, void *data)
 467{
 468    DeviceClass *dc = DEVICE_CLASS(klass);
 469
 470    dc->reset = xlnx_aes_reset;
 471    dc->realize = xlnx_aes_realize;
 472}
 473
 474static const TypeInfo xlnx_aes_info = {
 475    .name          = TYPE_XLNX_AES,
 476    .parent        = TYPE_DEVICE,
 477    .instance_size = sizeof(XlnxAES),
 478    .class_init    = xlnx_aes_class_init,
 479};
 480
 481static void xlnx_aes_types(void)
 482{
 483    type_register_static(&xlnx_aes_info);
 484}
 485
 486type_init(xlnx_aes_types)
 487