linux-user: Add LoongArch syscall support
[qemu/rayw.git] / crypto / der.c
blobf877390bbbedf7f28bbd91b09e0b15992746a64b
1 /*
2 * QEMU Crypto ASN.1 DER decoder
4 * Copyright (c) 2022 Bytedance
5 * Author: lei he <helei.sig11@bytedance.com>
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.
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.
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/>.
22 #include "qemu/osdep.h"
23 #include "crypto/der.h"
25 enum QCryptoDERTypeTag {
26 QCRYPTO_DER_TYPE_TAG_BOOL = 0x1,
27 QCRYPTO_DER_TYPE_TAG_INT = 0x2,
28 QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3,
29 QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4,
30 QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5,
31 QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6,
32 QCRYPTO_DER_TYPE_TAG_SEQ = 0x10,
33 QCRYPTO_DER_TYPE_TAG_SET = 0x11,
36 #define QCRYPTO_DER_CONSTRUCTED_MASK 0x20
37 #define QCRYPTO_DER_SHORT_LEN_MASK 0x80
39 static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
41 return **data;
44 static void qcrypto_der_cut_nbytes(const uint8_t **data,
45 size_t *dlen,
46 size_t nbytes)
48 *data += nbytes;
49 *dlen -= nbytes;
52 static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen)
54 uint8_t val = qcrypto_der_peek_byte(data, dlen);
56 qcrypto_der_cut_nbytes(data, dlen, 1);
58 return val;
61 static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx,
62 const uint8_t *value, size_t vlen,
63 Error **errp)
65 if (!cb) {
66 return 0;
69 return cb(ctx, value, vlen, errp);
72 static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen,
73 QCryptoDERDecodeCb cb, void *ctx,
74 Error **errp)
76 const uint8_t *value;
77 size_t vlen = 0;
78 uint8_t byte_count = qcrypto_der_cut_byte(data, dlen);
80 /* short format of definite-length */
81 if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) {
82 if (byte_count > *dlen) {
83 error_setg(errp, "Invalid content length: %u", byte_count);
84 return -1;
87 value = *data;
88 vlen = byte_count;
89 qcrypto_der_cut_nbytes(data, dlen, vlen);
91 if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
92 return -1;
94 return vlen;
97 /* Ignore highest bit */
98 byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK;
101 * size_t is enough to store the value of length, although the DER
102 * encoding standard supports larger length.
104 if (byte_count > sizeof(size_t)) {
105 error_setg(errp, "Invalid byte count of content length: %u",
106 byte_count);
107 return -1;
110 if (byte_count > *dlen) {
111 error_setg(errp, "Invalid content length: %u", byte_count);
112 return -1;
114 while (byte_count--) {
115 vlen <<= 8;
116 vlen += qcrypto_der_cut_byte(data, dlen);
119 if (vlen > *dlen) {
120 error_setg(errp, "Invalid content length: %zu", vlen);
121 return -1;
124 value = *data;
125 qcrypto_der_cut_nbytes(data, dlen, vlen);
127 if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
128 return -1;
130 return vlen;
133 static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
134 QCryptoDERDecodeCb cb, void *ctx,
135 Error **errp)
137 uint8_t val;
138 if (*dlen < 1) {
139 error_setg(errp, "Need more data");
140 return -1;
142 val = qcrypto_der_peek_byte(data, dlen);
144 /* must use definite length format */
145 if (val == QCRYPTO_DER_SHORT_LEN_MASK) {
146 error_setg(errp, "Only definite length format is allowed");
147 return -1;
150 return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
153 int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
154 QCryptoDERDecodeCb cb, void *ctx, Error **errp)
156 uint8_t tag;
157 if (*dlen < 1) {
158 error_setg(errp, "Need more data");
159 return -1;
161 tag = qcrypto_der_cut_byte(data, dlen);
163 /* INTEGER must encoded in primitive-form */
164 if (tag != QCRYPTO_DER_TYPE_TAG_INT) {
165 error_setg(errp, "Invalid integer type tag: %u", tag);
166 return -1;
169 return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
172 int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
173 QCryptoDERDecodeCb cb, void *ctx, Error **errp)
175 uint8_t tag;
176 if (*dlen < 1) {
177 error_setg(errp, "Need more data");
178 return -1;
180 tag = qcrypto_der_cut_byte(data, dlen);
182 /* SEQUENCE must use constructed form */
183 if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) {
184 error_setg(errp, "Invalid type sequence tag: %u", tag);
185 return -1;
188 return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);