xref: /openbmc/qemu/crypto/der.c (revision 34a8892d)
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  */
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 
112 static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
113 {
114     return **data;
115 }
116 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
371 void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx)
372 {
373     qcrypto_der_encode_cons_end(ctx);
374 }
375 
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 
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 
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 
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 
411 size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx)
412 {
413     return ctx->root.dlen;
414 }
415 
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