qemu/hw/misc/xlnx-aes-devkey.c
<<
>>
Prefs
   1/*
   2 * General utilities to assist simulation of device keys.
   3 *
   4 * Copyright (c) 2019 Xilinx Inc.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "qapi/error.h"
  26#include "crypto/secret.h"
  27#include "hw/misc/xlnx-aes.h"
  28
  29static int xlnx_aes_k256_xtob(const char *xs, uint8_t key[32], Error **errp)
  30{
  31    unsigned i;
  32
  33    for (i = 0; i < 64; i += 2) {
  34        unsigned k8;
  35        int j;
  36
  37        for (k8 = 0, j = i; j < (i + 2); j++) {
  38            gint x = g_ascii_xdigit_value(xs[j]);
  39
  40            if (x == -1) {
  41                if (xs[j]) {
  42                    error_setg(errp, "Error - \"%.*s[%c: not a hex digit]%s\"",
  43                               j, xs, xs[j], &xs[j + 1]);
  44                } else {
  45                    error_setg(errp, "Error - \"%s\": %d hex digits < 64",
  46                               xs, j);
  47                }
  48                return -1;
  49            }
  50
  51            k8 = (k8 << 4) | (x & 15);
  52        }
  53
  54        key[i / 2] = k8;
  55    }
  56
  57    return 0;
  58}
  59
  60static char *xlnx_aes_k256_get_secret(Object *obj, const char *id_prop,
  61                                      Error **errp)
  62{
  63    Error *local_err = NULL;
  64    char *secret_id, *data = NULL;
  65    int rc = 0;
  66
  67    /* "No id" is treated as no secret */
  68    secret_id = object_property_get_str(obj, id_prop, NULL);
  69    if (!secret_id) {
  70        goto done;
  71    }
  72
  73    data = qcrypto_secret_lookup_as_utf8(secret_id, &local_err);
  74    if (data) {
  75        data = g_strchomp(data);
  76        goto done;
  77    }
  78
  79    /*
  80     * Object-not-found is handled gracefully by setting default.
  81     * Unfortunately, the only way to sniff out not-found is by
  82     * string-matching, a rather unrobust way.
  83     */
  84    if (!local_err) {
  85        error_setg(errp, "Secret id '%s' lookup failed: Unknown error",
  86                   secret_id);
  87        rc = -1;
  88    } else if (strncmp(error_get_pretty(local_err), "No secret with id", 17)) {
  89        error_propagate(errp, local_err);
  90        rc = -1;
  91    } else {
  92        error_free(local_err);
  93    }
  94
  95 done:
  96    g_free(secret_id);
  97    if (!rc && !data) {
  98        data = g_strdup("");
  99    }
 100
 101    return data;
 102}
 103
 104int xlnx_aes_k256_get_provided_i(Object *obj, const char *id_prop,
 105                                 const char *given_default,
 106                                 uint8_t key[32], Error **errp)
 107{
 108    static const char builtin_default[] =
 109        /* A pattern with all 32 bytes being unique */
 110        "01234567" "89abcdef" "02468ace" "13579bdf"
 111        "12345678" "9abcdef0" "2468ace0" "3579bdf1";
 112
 113    const char *xd;
 114    char *data;
 115    int rc;
 116
 117    assert(key != NULL);
 118    assert(obj != NULL);
 119    assert(id_prop != NULL);
 120    assert(id_prop[0] != '\0');
 121
 122    /* Abort on unhandled errors */
 123    if (!errp) {
 124        errp = &error_abort;
 125    }
 126
 127    data = xlnx_aes_k256_get_secret(obj, id_prop, errp);
 128    if (!data) {
 129        return -1;
 130    }
 131
 132    xd = data;
 133    if (!xd[0]) {
 134        xd = given_default ? given_default : builtin_default;
 135    }
 136
 137    rc = xlnx_aes_k256_xtob(xd, key, errp);
 138    g_free(data);
 139
 140    return rc;
 141}
 142
 143static uint32_t xlnx_calc_row_crc(uint32_t prev_crc, uint32_t data,
 144                                  uint32_t addr)
 145{
 146    /* A table for 7-bit slicing */
 147    static const uint32_t crc_tab[128] = {
 148        0x00000000, 0xe13b70f7, 0xc79a971f, 0x26a1e7e8,
 149        0x8ad958cf, 0x6be22838, 0x4d43cfd0, 0xac78bf27,
 150        0x105ec76f, 0xf165b798, 0xd7c45070, 0x36ff2087,
 151        0x9a879fa0, 0x7bbcef57, 0x5d1d08bf, 0xbc267848,
 152        0x20bd8ede, 0xc186fe29, 0xe72719c1, 0x061c6936,
 153        0xaa64d611, 0x4b5fa6e6, 0x6dfe410e, 0x8cc531f9,
 154        0x30e349b1, 0xd1d83946, 0xf779deae, 0x1642ae59,
 155        0xba3a117e, 0x5b016189, 0x7da08661, 0x9c9bf696,
 156        0x417b1dbc, 0xa0406d4b, 0x86e18aa3, 0x67dafa54,
 157        0xcba24573, 0x2a993584, 0x0c38d26c, 0xed03a29b,
 158        0x5125dad3, 0xb01eaa24, 0x96bf4dcc, 0x77843d3b,
 159        0xdbfc821c, 0x3ac7f2eb, 0x1c661503, 0xfd5d65f4,
 160        0x61c69362, 0x80fde395, 0xa65c047d, 0x4767748a,
 161        0xeb1fcbad, 0x0a24bb5a, 0x2c855cb2, 0xcdbe2c45,
 162        0x7198540d, 0x90a324fa, 0xb602c312, 0x5739b3e5,
 163        0xfb410cc2, 0x1a7a7c35, 0x3cdb9bdd, 0xdde0eb2a,
 164        0x82f63b78, 0x63cd4b8f, 0x456cac67, 0xa457dc90,
 165        0x082f63b7, 0xe9141340, 0xcfb5f4a8, 0x2e8e845f,
 166        0x92a8fc17, 0x73938ce0, 0x55326b08, 0xb4091bff,
 167        0x1871a4d8, 0xf94ad42f, 0xdfeb33c7, 0x3ed04330,
 168        0xa24bb5a6, 0x4370c551, 0x65d122b9, 0x84ea524e,
 169        0x2892ed69, 0xc9a99d9e, 0xef087a76, 0x0e330a81,
 170        0xb21572c9, 0x532e023e, 0x758fe5d6, 0x94b49521,
 171        0x38cc2a06, 0xd9f75af1, 0xff56bd19, 0x1e6dcdee,
 172        0xc38d26c4, 0x22b65633, 0x0417b1db, 0xe52cc12c,
 173        0x49547e0b, 0xa86f0efc, 0x8ecee914, 0x6ff599e3,
 174        0xd3d3e1ab, 0x32e8915c, 0x144976b4, 0xf5720643,
 175        0x590ab964, 0xb831c993, 0x9e902e7b, 0x7fab5e8c,
 176        0xe330a81a, 0x020bd8ed, 0x24aa3f05, 0xc5914ff2,
 177        0x69e9f0d5, 0x88d28022, 0xae7367ca, 0x4f48173d,
 178        0xf36e6f75, 0x12551f82, 0x34f4f86a, 0xd5cf889d,
 179        0x79b737ba, 0x988c474d, 0xbe2da0a5, 0x5f16d052
 180    };
 181
 182    /*
 183     * eFuse calculation is shown here:
 184     *  https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_utils.c#L1496
 185     *
 186     * Each u32 word is appended a 5-bit value, for a total of 37 bits; see:
 187     *  https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_utils.c#L1356
 188     */
 189    uint32_t crc = prev_crc;
 190    const unsigned rshf = 7;
 191    const uint32_t im = (1 << rshf) - 1;
 192    const uint32_t rm = (1 << (32 - rshf)) - 1;
 193    const uint32_t i2 = (1 << 2) - 1;
 194    const uint32_t r2 = (1 << 30) - 1;
 195
 196    unsigned j;
 197    uint32_t i, r;
 198    uint64_t w;
 199
 200    w = (uint64_t)(addr) << 32;
 201    w |= data;
 202
 203    /* Feed 35 bits, in 5 rounds, each a slice of 7 bits */
 204    for (j = 0; j < 5; j++) {
 205        r = rm & (crc >> rshf);
 206        i = im & (crc ^ w);
 207        crc = crc_tab[i] ^ r;
 208
 209        w >>= rshf;
 210    }
 211
 212    /* Feed the remaining 2 bits */
 213    r = r2 & (crc >> 2);
 214    i = i2 & (crc ^ w);
 215    crc = crc_tab[i << (rshf - 2)] ^ r;
 216
 217    return crc;
 218}
 219
 220uint32_t xlnx_calc_crc(const uint32_t *data, unsigned data_length)
 221{
 222    uint32_t crc = 0;
 223    unsigned i;
 224
 225    i = data_length;
 226    while (i--) {
 227        uint32_t addr = i + 1;
 228
 229        crc = xlnx_calc_row_crc(crc, data[i], addr);
 230    }
 231
 232    return crc;
 233}
 234
 235/*
 236 * Find AES256 key CRC for bbram and efuse.
 237 * k256[0]: BBRAM_0 or row_of(EFUSE_AES_START)
 238 * k256[7]: BBRAM_7 or row_of(EFUSE_AES_END)
 239 */
 240uint32_t xlnx_aes_k256_crc(const uint32_t *k256, unsigned zpad_cnt)
 241{
 242    uint32_t crc = 0;
 243    unsigned k;
 244
 245    /*
 246     * BBRAM check has a zero-u32 prepended; see:
 247     *  https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_bbramps_zynqmp.c#L311
 248     */
 249    k = 8 + zpad_cnt;
 250    while (k--) {
 251        uint32_t data = k > 7 ? 0 : k256[k];
 252        uint32_t addr = k + 1;
 253
 254        crc = xlnx_calc_row_crc(crc, data, addr);
 255    }
 256
 257    return crc;
 258}
 259
 260void xlnx_aes_k256_swap32_i(uint8_t dst[32], const uint8_t src[32])
 261{
 262    /*
 263     * Convert each group of 32 bits,
 264     *  From: byte-order used by Xilinx embeddedsw to specify hex-string key
 265     *        (same as hex-string key parsed by xlnx_aes_k256_get_provided()).
 266     *  Into: byte-order used by zynqmp_aes_key_update()
 267     *
 268     * zynqmp_aes_key_update() expects:
 269     * 1. Each 32-bit in cpu endian; yet,
 270     * 2. The order of 8 32b-words in big endian.
 271     */
 272    unsigned i;
 273    const void *dp = dst, *sp = src;
 274
 275    /* Ok to be 'in-place' swap.  Not ok to be partial overlap. */
 276    if (dp != sp) {
 277        const void *de = &dst[31];
 278        const void *se = &src[31];
 279
 280        assert(de < sp || se < dp);
 281    }
 282
 283    for (i = 0; i < 32; i += 4) {
 284        uint32_t v;
 285
 286        v = ldl_be_p(&src[i]);
 287        stl_he_p(&dst[i], v);
 288    }
 289}
 290
 291bool xlnx_aes_k256_is_zero_i(const uint8_t key[32])
 292{
 293    uint64_t q0, q1, q2, q3;
 294
 295    q0 = ldq_he_p(key);
 296    q1 = ldq_he_p(key + 8);
 297    q2 = ldq_he_p(key + 16);
 298    q3 = ldq_he_p(key + 24);
 299
 300    return !(q0 | q1 | q2 | q3);
 301}
 302