]> git.proxmox.com Git - mirror_qemu.git/blame - crypto/der.c
bsd-user: Implement revoke, access, eaccess and faccessat
[mirror_qemu.git] / crypto / der.c
CommitLineData
99d423f1
LH
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
25enum 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,
34};
35
36#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20
37#define QCRYPTO_DER_SHORT_LEN_MASK 0x80
38
39static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
40{
41 return **data;
42}
43
44static void qcrypto_der_cut_nbytes(const uint8_t **data,
45 size_t *dlen,
46 size_t nbytes)
47{
48 *data += nbytes;
49 *dlen -= nbytes;
50}
51
52static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen)
53{
54 uint8_t val = qcrypto_der_peek_byte(data, dlen);
55
56 qcrypto_der_cut_nbytes(data, dlen, 1);
57
58 return val;
59}
60
61static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx,
62 const uint8_t *value, size_t vlen,
63 Error **errp)
64{
65 if (!cb) {
66 return 0;
67 }
68
69 return cb(ctx, value, vlen, errp);
70}
71
72static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen,
73 QCryptoDERDecodeCb cb, void *ctx,
74 Error **errp)
75{
76 const uint8_t *value;
77 size_t vlen = 0;
78 uint8_t byte_count = qcrypto_der_cut_byte(data, dlen);
79
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;
85 }
86
87 value = *data;
88 vlen = byte_count;
89 qcrypto_der_cut_nbytes(data, dlen, vlen);
90
91 if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
92 return -1;
93 }
94 return vlen;
95 }
96
97 /* Ignore highest bit */
98 byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK;
99
100 /*
101 * size_t is enough to store the value of length, although the DER
102 * encoding standard supports larger length.
103 */
104 if (byte_count > sizeof(size_t)) {
105 error_setg(errp, "Invalid byte count of content length: %u",
106 byte_count);
107 return -1;
108 }
109
110 if (byte_count > *dlen) {
111 error_setg(errp, "Invalid content length: %u", byte_count);
112 return -1;
113 }
114 while (byte_count--) {
115 vlen <<= 8;
116 vlen += qcrypto_der_cut_byte(data, dlen);
117 }
118
119 if (vlen > *dlen) {
120 error_setg(errp, "Invalid content length: %zu", vlen);
121 return -1;
122 }
123
124 value = *data;
125 qcrypto_der_cut_nbytes(data, dlen, vlen);
126
127 if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) {
128 return -1;
129 }
130 return vlen;
131}
132
133static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
134 QCryptoDERDecodeCb cb, void *ctx,
135 Error **errp)
136{
137 uint8_t val;
138 if (*dlen < 1) {
139 error_setg(errp, "Need more data");
140 return -1;
141 }
142 val = qcrypto_der_peek_byte(data, dlen);
143
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;
148 }
149
150 return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
151}
152
153int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
154 QCryptoDERDecodeCb cb, void *ctx, Error **errp)
155{
156 uint8_t tag;
157 if (*dlen < 1) {
158 error_setg(errp, "Need more data");
159 return -1;
160 }
161 tag = qcrypto_der_cut_byte(data, dlen);
162
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;
167 }
168
169 return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
170}
171
172int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
173 QCryptoDERDecodeCb cb, void *ctx, Error **errp)
174{
175 uint8_t tag;
176 if (*dlen < 1) {
177 error_setg(errp, "Need more data");
178 return -1;
179 }
180 tag = qcrypto_der_cut_byte(data, dlen);
181
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;
186 }
187
188 return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
189}