qemu/crypto/der.c
<<
>>
Prefs
   1/*
   2 * QEMU Crypto ASN.1 DER decoder
   3 *
   4 * Copyright (c) 2022 Bytedance
   5 * Author: lei he <helei.sig11@bytedance.com>
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19 *
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "crypto/der.h"
  24
  25typedef struct QCryptoDerEncodeNode {
  26    uint8_t tag;
  27    struct QCryptoDerEncodeNode *parent;
  28    struct QCryptoDerEncodeNode *next;
  29    /* for constructed type, data is null */
  30    const uint8_t *data;
  31    size_t dlen;
  32} QCryptoDerEncodeNode;
  33
  34typedef struct QCryptoEncodeContext {
  35    QCryptoDerEncodeNode root;
  36    QCryptoDerEncodeNode *current_parent;
  37    QCryptoDerEncodeNode *tail;
  38} QCryptoEncodeContext;
  39
  40enum QCryptoDERTypeTag {
  41    QCRYPTO_DER_TYPE_TAG_BOOL = 0x1,
  42    QCRYPTO_DER_TYPE_TAG_INT = 0x2,
  43    QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3,
  44    QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4,
  45    QCRYPTO_DER_TYPE_TAG_NULL = 0x5,
  46    QCRYPTO_DER_TYPE_TAG_OID = 0x6,
  47    QCRYPTO_DER_TYPE_TAG_SEQ = 0x10,
  48    QCRYPTO_DER_TYPE_TAG_SET = 0x11,
  49};
  50
  51enum QCryptoDERTagClass {
  52    QCRYPTO_DER_TAG_CLASS_UNIV = 0x0,
  53    QCRYPTO_DER_TAG_CLASS_APPL = 0x1,
  54    QCRYPTO_DER_TAG_CLASS_CONT = 0x2,
  55    QCRYPTO_DER_TAG_CLASS_PRIV = 0x3,
  56};
  57
  58enum QCryptoDERTagEnc {
  59    QCRYPTO_DER_TAG_ENC_PRIM = 0x0,
  60    QCRYPTO_DER_TAG_ENC_CONS = 0x1,
  61};
  62
  63#define QCRYPTO_DER_TAG_ENC_MASK 0x20
  64#define QCRYPTO_DER_TAG_ENC_SHIFT 5
  65
  66#define QCRYPTO_DER_TAG_CLASS_MASK 0xc0
  67#define QCRYPTO_DER_TAG_CLASS_SHIFT 6
  68
  69#define QCRYPTO_DER_TAG_VAL_MASK 0x1f
  70#define QCRYPTO_DER_SHORT_LEN_MASK 0x80
  71
  72#define QCRYPTO_DER_TAG(class, enc, val)           \
  73    (((class) << QCRYPTO_DER_TAG_CLASS_SHIFT) |    \
  74     ((enc) << QCRYPTO_DER_TAG_ENC_SHIFT) | (val))
  75
  76/**
  77 * qcrypto_der_encode_length:
  78 * @src_len: the length of source data
  79 * @dst: distination to save the encoded 'length', if dst is NULL, only compute
  80 * the expected buffer size in bytes.
  81 * @dst_len: output parameter, indicates how many bytes wrote.
  82 *
  83 * Encode the 'length' part of TLV tuple.
  84 */
  85static void qcrypto_der_encode_length(size_t src_len,
  86                                      uint8_t *dst, size_t *dst_len)
  87{
  88    size_t max_length = 0xFF;
  89    uint8_t length_bytes = 0, header_byte;
  90
  91    if (src_len < QCRYPTO_DER_SHORT_LEN_MASK) {
  92        header_byte = src_len;
  93        *dst_len = 1;
  94    } else {
  95        for (length_bytes = 1; max_length < src_len; length_bytes++) {
  96            max_length = (max_length << 8) + max_length;
  97        }
  98        header_byte = length_bytes;
  99        header_byte |= QCRYPTO_DER_SHORT_LEN_MASK;
 100        *dst_len = length_bytes + 1;
 101    }
 102    if (!dst) {
 103        return;
 104    }
 105    *dst++ = header_byte;
 106    /* Bigendian length bytes */
 107    for (; length_bytes > 0; length_bytes--) {
 108        *dst++ = ((src_len >> (length_bytes - 1) * 8) & 0xFF);
 109    }
 110}
 111
 112static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
 113{
 114    return **data;
 115}
 116
 117static void qcrypto_der_cut_nbytes(const uint8_t **data,
 118                                   size_t *dlen,
 119                                   size_t nbytes)
 120{
 121    *data += nbytes;
 122    *dlen -= nbytes;
 123}
 124
 125static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen)
 126{
 127    uint8_t val = qcrypto_der_peek_byte(data, dlen);
 128
 129    qcrypto_der_cut_nbytes(data, dlen, 1);
 130
 131    return val;
 132}
 133
 134static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx,
 135                                       const uint8_t *value, size_t vlen,
 136                                       Error **errp)
 137{
 138    if (!cb) {
 139        return 0;
 140    }
 141
 142    return cb(ctx, value, vlen, errp);
 143}
 144
 145static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen,
 146                                             QCryptoDERDecodeCb cb, void *ctx,
 147                                             Error **errp)
 148{
 149    const uint8_t *value;
 150    size_t vlen = 0;
 151    uint8_t byte_count = qcrypto_der_cut_byte(data, dlen);
 152
 153    /* short format of definite-length */
 154    if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) {
 155        if (byte_count > *dlen) {
 156            error_setg(errp, "Invalid content length: %u", byte_count);
 157            return -1;
 158        }
 159
 160        value = *data;
 161        vlen = byte_count;
 162        qcrypto_der_cut_nbytes(data, dlen, vlen);
 163
 164        if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
 165            return -1;
 166        }
 167        return vlen;
 168    }
 169
 170    /* Ignore highest bit */
 171    byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK;
 172
 173    /*
 174     * size_t is enough to store the value of length, although the DER
 175     * encoding standard supports larger length.
 176     */
 177    if (byte_count > sizeof(size_t)) {
 178        error_setg(errp, "Invalid byte count of content length: %u",
 179                   byte_count);
 180        return -1;
 181    }
 182
 183    if (byte_count > *dlen) {
 184        error_setg(errp, "Invalid content length: %u", byte_count);
 185        return -1;
 186    }
 187    while (byte_count--) {
 188        vlen <<= 8;
 189        vlen += qcrypto_der_cut_byte(data, dlen);
 190    }
 191
 192    if (vlen > *dlen) {
 193        error_setg(errp, "Invalid content length: %zu", vlen);
 194        return -1;
 195    }
 196
 197    value = *data;
 198    qcrypto_der_cut_nbytes(data, dlen, vlen);
 199
 200    if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
 201        return -1;
 202    }
 203    return vlen;
 204}
 205
 206static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
 207                                    QCryptoDERDecodeCb cb, void *ctx,
 208                                    Error **errp)
 209{
 210    uint8_t val;
 211    if (*dlen < 1) {
 212        error_setg(errp, "Need more data");
 213        return -1;
 214    }
 215    val = qcrypto_der_peek_byte(data, dlen);
 216
 217    /* must use definite length format */
 218    if (val == QCRYPTO_DER_SHORT_LEN_MASK) {
 219        error_setg(errp, "Only definite length format is allowed");
 220        return -1;
 221    }
 222
 223    return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
 224}
 225
 226static int qcrypto_der_decode_tlv(const uint8_t expected_tag,
 227                                  const uint8_t **data, size_t *dlen,
 228                                  QCryptoDERDecodeCb cb,
 229                                  void *ctx, Error **errp)
 230{
 231    const uint8_t *saved_data = *data;
 232    size_t saved_dlen = *dlen;
 233    uint8_t tag;
 234    int data_length;
 235
 236    if (*dlen < 1) {
 237        error_setg(errp, "Need more data");
 238        return -1;
 239    }
 240    tag = qcrypto_der_cut_byte(data, dlen);
 241    if (tag != expected_tag) {
 242        error_setg(errp, "Unexpected tag: expected: %u, actual: %u",
 243                   expected_tag, tag);
 244        goto error;
 245    }
 246
 247    data_length = qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
 248    if (data_length < 0) {
 249        goto error;
 250    }
 251    return data_length;
 252
 253error:
 254    *data = saved_data;
 255    *dlen = saved_dlen;
 256    return -1;
 257}
 258
 259int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
 260                           QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 261{
 262    const uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 263                                        QCRYPTO_DER_TAG_ENC_PRIM,
 264                                        QCRYPTO_DER_TYPE_TAG_INT);
 265    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 266}
 267
 268int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
 269                           QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 270{
 271    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 272                                  QCRYPTO_DER_TAG_ENC_CONS,
 273                                  QCRYPTO_DER_TYPE_TAG_SEQ);
 274    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 275}
 276
 277int qcrypto_der_decode_octet_str(const uint8_t **data, size_t *dlen,
 278                                 QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 279{
 280    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 281                                  QCRYPTO_DER_TAG_ENC_PRIM,
 282                                  QCRYPTO_DER_TYPE_TAG_OCT_STR);
 283    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 284}
 285
 286int qcrypto_der_decode_bit_str(const uint8_t **data, size_t *dlen,
 287                               QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 288{
 289    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 290                                  QCRYPTO_DER_TAG_ENC_PRIM,
 291                                  QCRYPTO_DER_TYPE_TAG_BIT_STR);
 292    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 293}
 294
 295int qcrypto_der_decode_oid(const uint8_t **data, size_t *dlen,
 296                           QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 297{
 298    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 299                                  QCRYPTO_DER_TAG_ENC_PRIM,
 300                                  QCRYPTO_DER_TYPE_TAG_OID);
 301    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 302}
 303
 304int qcrypto_der_decode_ctx_tag(const uint8_t **data, size_t *dlen, int tag_id,
 305                               QCryptoDERDecodeCb cb, void *ctx, Error **errp)
 306{
 307    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_CONT,
 308                                  QCRYPTO_DER_TAG_ENC_CONS,
 309                                  tag_id);
 310    return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
 311}
 312
 313static void qcrypto_der_encode_prim(QCryptoEncodeContext *ctx, uint8_t tag,
 314                                    const uint8_t *data, size_t dlen)
 315{
 316    QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1);
 317    size_t nbytes_len;
 318
 319    node->tag = tag;
 320    node->data = data;
 321    node->dlen = dlen;
 322    node->parent = ctx->current_parent;
 323
 324    qcrypto_der_encode_length(dlen, NULL, &nbytes_len);
 325    /* 1 byte for Tag, nbyte_len for Length, and dlen for Value */
 326    node->parent->dlen += 1 + nbytes_len + dlen;
 327
 328    ctx->tail->next = node;
 329    ctx->tail = node;
 330}
 331
 332QCryptoEncodeContext *qcrypto_der_encode_ctx_new(void)
 333{
 334    QCryptoEncodeContext *ctx = g_new0(QCryptoEncodeContext, 1);
 335    ctx->current_parent = &ctx->root;
 336    ctx->tail = &ctx->root;
 337    return ctx;
 338}
 339
 340static void qcrypto_der_encode_cons_begin(QCryptoEncodeContext *ctx,
 341                                          uint8_t tag)
 342{
 343    QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1);
 344
 345    node->tag = tag;
 346    node->parent = ctx->current_parent;
 347    ctx->current_parent = node;
 348    ctx->tail->next = node;
 349    ctx->tail = node;
 350}
 351
 352static void qcrypto_der_encode_cons_end(QCryptoEncodeContext *ctx)
 353{
 354    QCryptoDerEncodeNode *cons_node = ctx->current_parent;
 355    size_t nbytes_len;
 356
 357    qcrypto_der_encode_length(cons_node->dlen, NULL, &nbytes_len);
 358    /* 1 byte for Tag, nbyte_len for Length, and dlen for Value */
 359    cons_node->parent->dlen += 1 + nbytes_len + cons_node->dlen;
 360    ctx->current_parent = cons_node->parent;
 361}
 362
 363void qcrypto_der_encode_seq_begin(QCryptoEncodeContext *ctx)
 364{
 365    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 366                                  QCRYPTO_DER_TAG_ENC_CONS,
 367                                  QCRYPTO_DER_TYPE_TAG_SEQ);
 368    qcrypto_der_encode_cons_begin(ctx, tag);
 369}
 370
 371void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx)
 372{
 373    qcrypto_der_encode_cons_end(ctx);
 374}
 375
 376void qcrypto_der_encode_oid(QCryptoEncodeContext *ctx,
 377                            const uint8_t *src, size_t src_len)
 378{
 379    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 380                                  QCRYPTO_DER_TAG_ENC_PRIM,
 381                                  QCRYPTO_DER_TYPE_TAG_OID);
 382    qcrypto_der_encode_prim(ctx, tag, src, src_len);
 383}
 384
 385void qcrypto_der_encode_int(QCryptoEncodeContext *ctx,
 386                            const uint8_t *src, size_t src_len)
 387{
 388    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 389                                  QCRYPTO_DER_TAG_ENC_PRIM,
 390                                  QCRYPTO_DER_TYPE_TAG_INT);
 391    qcrypto_der_encode_prim(ctx, tag, src, src_len);
 392}
 393
 394void qcrypto_der_encode_null(QCryptoEncodeContext *ctx)
 395{
 396    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 397                                  QCRYPTO_DER_TAG_ENC_PRIM,
 398                                  QCRYPTO_DER_TYPE_TAG_NULL);
 399    qcrypto_der_encode_prim(ctx, tag, NULL, 0);
 400}
 401
 402void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx,
 403                                  const uint8_t *src, size_t src_len)
 404{
 405    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 406                                  QCRYPTO_DER_TAG_ENC_PRIM,
 407                                  QCRYPTO_DER_TYPE_TAG_OCT_STR);
 408    qcrypto_der_encode_prim(ctx, tag, src, src_len);
 409}
 410
 411void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx)
 412{
 413    uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
 414                                  QCRYPTO_DER_TAG_ENC_PRIM,
 415                                  QCRYPTO_DER_TYPE_TAG_OCT_STR);
 416    qcrypto_der_encode_cons_begin(ctx, tag);
 417}
 418
 419void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx)
 420{
 421    qcrypto_der_encode_cons_end(ctx);
 422}
 423
 424size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx)
 425{
 426    return ctx->root.dlen;
 427}
 428
 429void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx,
 430                                           uint8_t *dst)
 431{
 432    QCryptoDerEncodeNode *node, *prev;
 433    size_t len;
 434
 435    for (prev = &ctx->root;
 436         (node = prev->next) && (prev->next = node->next, 1);) {
 437        /* Tag */
 438        *dst++ = node->tag;
 439
 440        /* Length */
 441        qcrypto_der_encode_length(node->dlen, dst, &len);
 442        dst += len;
 443
 444        /* Value */
 445        if (node->data) {
 446            memcpy(dst, node->data, node->dlen);
 447            dst += node->dlen;
 448        }
 449        g_free(node);
 450    }
 451    g_free(ctx);
 452}
 453