xref: /openbmc/qemu/crypto/der.c (revision e51d8fbb7e673e487e98327fc067700b5a3edf30)
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  
25  typedef 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  
34  typedef struct QCryptoEncodeContext {
35      QCryptoDerEncodeNode root;
36      QCryptoDerEncodeNode *current_parent;
37      QCryptoDerEncodeNode *tail;
38  } QCryptoEncodeContext;
39  
40  enum 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  
51  enum 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  
58  enum 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: destination 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   */
qcrypto_der_encode_length(size_t src_len,uint8_t * dst,size_t * dst_len)85  static 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  
qcrypto_der_peek_byte(const uint8_t ** data,size_t * dlen)112  static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
113  {
114      return **data;
115  }
116  
qcrypto_der_cut_nbytes(const uint8_t ** data,size_t * dlen,size_t nbytes)117  static 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  
qcrypto_der_cut_byte(const uint8_t ** data,size_t * dlen)125  static 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  
qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb,void * ctx,const uint8_t * value,size_t vlen,Error ** errp)134  static 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  
qcrypto_der_extract_definite_data(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)145  static 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  
qcrypto_der_extract_data(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)206  static 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  
qcrypto_der_decode_tlv(const uint8_t expected_tag,const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)226  static 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  
253  error:
254      *data = saved_data;
255      *dlen = saved_dlen;
256      return -1;
257  }
258  
qcrypto_der_decode_int(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)259  int 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  
qcrypto_der_decode_seq(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)268  int 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  
qcrypto_der_decode_octet_str(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)277  int 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  
qcrypto_der_decode_bit_str(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)286  int 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  
qcrypto_der_decode_oid(const uint8_t ** data,size_t * dlen,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)295  int 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  
qcrypto_der_decode_ctx_tag(const uint8_t ** data,size_t * dlen,int tag_id,QCryptoDERDecodeCb cb,void * ctx,Error ** errp)304  int 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  
qcrypto_der_encode_prim(QCryptoEncodeContext * ctx,uint8_t tag,const uint8_t * data,size_t dlen)313  static 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  
qcrypto_der_encode_ctx_new(void)332  QCryptoEncodeContext *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  
qcrypto_der_encode_cons_begin(QCryptoEncodeContext * ctx,uint8_t tag)340  static 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  
qcrypto_der_encode_cons_end(QCryptoEncodeContext * ctx)352  static 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  
qcrypto_der_encode_seq_begin(QCryptoEncodeContext * ctx)363  void 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  
qcrypto_der_encode_seq_end(QCryptoEncodeContext * ctx)371  void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx)
372  {
373      qcrypto_der_encode_cons_end(ctx);
374  }
375  
qcrypto_der_encode_oid(QCryptoEncodeContext * ctx,const uint8_t * src,size_t src_len)376  void 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  
qcrypto_der_encode_int(QCryptoEncodeContext * ctx,const uint8_t * src,size_t src_len)385  void 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  
qcrypto_der_encode_null(QCryptoEncodeContext * ctx)394  void 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  
qcrypto_der_encode_octet_str(QCryptoEncodeContext * ctx,const uint8_t * src,size_t src_len)402  void 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  
qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext * ctx)411  size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx)
412  {
413      return ctx->root.dlen;
414  }
415  
qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext * ctx,uint8_t * dst)416  void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx,
417                                             uint8_t *dst)
418  {
419      QCryptoDerEncodeNode *node, *prev;
420      size_t len;
421  
422      for (prev = &ctx->root;
423           (node = prev->next) && (prev->next = node->next, 1);) {
424          /* Tag */
425          *dst++ = node->tag;
426  
427          /* Length */
428          qcrypto_der_encode_length(node->dlen, dst, &len);
429          dst += len;
430  
431          /* Value */
432          if (node->data) {
433              memcpy(dst, node->data, node->dlen);
434              dst += node->dlen;
435          }
436          g_free(node);
437      }
438      g_free(ctx);
439  }
440