blob: 4123ac3c1008731234c3abea8342bf08c4bd4bd1 [file] [log] [blame]
Paul Bakkerbdb912d2012-02-13 23:11:30 +00001/*
2 * ASN.1 buffer writing functionality
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakkerbdb912d2012-02-13 23:11:30 +000018 */
19
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakkerbdb912d2012-02-13 23:11:30 +000021
Agathiyan Bragadeesh86dc0852023-09-04 14:53:30 +010022#if defined(MBEDTLS_ASN1_WRITE_C) || defined(MBEDTLS_X509_USE_C)
Paul Bakkerbdb912d2012-02-13 23:11:30 +000023
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/asn1write.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000025#include "mbedtls/error.h"
Paul Bakkerbdb912d2012-02-13 23:11:30 +000026
Rich Evans00ab4702015-02-06 13:43:58 +000027#include <string.h>
28
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000029#include "mbedtls/platform.h"
Paul Bakker59ba59f2013-09-09 11:26:00 +020030
Gilles Peskine449bd832023-01-11 14:50:10 +010031int mbedtls_asn1_write_len(unsigned char **p, const unsigned char *start, size_t len)
Paul Bakkerbdb912d2012-02-13 23:11:30 +000032{
Gilles Peskine449bd832023-01-11 14:50:10 +010033 if (len < 0x80) {
34 if (*p - start < 1) {
35 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
36 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +000037
Paul Bakkerb9cfaa02013-10-11 18:58:55 +020038 *--(*p) = (unsigned char) len;
Gilles Peskine449bd832023-01-11 14:50:10 +010039 return 1;
Paul Bakkerbdb912d2012-02-13 23:11:30 +000040 }
41
Gilles Peskine449bd832023-01-11 14:50:10 +010042 if (len <= 0xFF) {
43 if (*p - start < 2) {
44 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
45 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +000046
Paul Bakkerb9cfaa02013-10-11 18:58:55 +020047 *--(*p) = (unsigned char) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +000048 *--(*p) = 0x81;
Gilles Peskine449bd832023-01-11 14:50:10 +010049 return 2;
Paul Bakkerbdb912d2012-02-13 23:11:30 +000050 }
51
Gilles Peskine449bd832023-01-11 14:50:10 +010052 if (len <= 0xFFFF) {
53 if (*p - start < 3) {
54 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
55 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +000056
Gilles Peskine449bd832023-01-11 14:50:10 +010057 *--(*p) = MBEDTLS_BYTE_0(len);
58 *--(*p) = MBEDTLS_BYTE_1(len);
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010059 *--(*p) = 0x82;
Gilles Peskine449bd832023-01-11 14:50:10 +010060 return 3;
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010061 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +000062
Gilles Peskine449bd832023-01-11 14:50:10 +010063 if (len <= 0xFFFFFF) {
64 if (*p - start < 4) {
65 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
66 }
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010067
Gilles Peskine449bd832023-01-11 14:50:10 +010068 *--(*p) = MBEDTLS_BYTE_0(len);
69 *--(*p) = MBEDTLS_BYTE_1(len);
70 *--(*p) = MBEDTLS_BYTE_2(len);
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010071 *--(*p) = 0x83;
Gilles Peskine449bd832023-01-11 14:50:10 +010072 return 4;
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010073 }
74
David Horstmann059848f2022-10-25 10:16:45 +010075 int len_is_valid = 1;
Azim Khan45b79cf2018-05-23 16:55:16 +010076#if SIZE_MAX > 0xFFFFFFFF
Gilles Peskine449bd832023-01-11 14:50:10 +010077 len_is_valid = (len <= 0xFFFFFFFF);
Azim Khan45b79cf2018-05-23 16:55:16 +010078#endif
Gilles Peskine449bd832023-01-11 14:50:10 +010079 if (len_is_valid) {
80 if (*p - start < 5) {
81 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
82 }
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010083
Gilles Peskine449bd832023-01-11 14:50:10 +010084 *--(*p) = MBEDTLS_BYTE_0(len);
85 *--(*p) = MBEDTLS_BYTE_1(len);
86 *--(*p) = MBEDTLS_BYTE_2(len);
87 *--(*p) = MBEDTLS_BYTE_3(len);
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010088 *--(*p) = 0x84;
Gilles Peskine449bd832023-01-11 14:50:10 +010089 return 5;
Paul Bakkerc7d6bd42016-07-14 11:39:56 +010090 }
91
Gilles Peskine449bd832023-01-11 14:50:10 +010092 return MBEDTLS_ERR_ASN1_INVALID_LENGTH;
Paul Bakkerbdb912d2012-02-13 23:11:30 +000093}
94
Gilles Peskine449bd832023-01-11 14:50:10 +010095int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start, unsigned char tag)
Paul Bakkerbdb912d2012-02-13 23:11:30 +000096{
Gilles Peskine449bd832023-01-11 14:50:10 +010097 if (*p - start < 1) {
98 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
99 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000100
101 *--(*p) = tag;
102
Gilles Peskine449bd832023-01-11 14:50:10 +0100103 return 1;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000104}
Agathiyan Bragadeesh86dc0852023-09-04 14:53:30 +0100105#endif /* MBEDTLS_ASN1_WRITE_C || MBEDTLS_X509_USE_C */
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000106
Agathiyan Bragadeesh86dc0852023-09-04 14:53:30 +0100107#if defined(MBEDTLS_ASN1_WRITE_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100108int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start,
109 const unsigned char *buf, size_t size)
Paul Bakker9852d002013-08-26 17:56:37 +0200110{
111 size_t len = 0;
112
Gilles Peskine449bd832023-01-11 14:50:10 +0100113 if (*p < start || (size_t) (*p - start) < size) {
114 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
115 }
Paul Bakker9852d002013-08-26 17:56:37 +0200116
117 len = size;
118 (*p) -= len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100119 memcpy(*p, buf, len);
Paul Bakker9852d002013-08-26 17:56:37 +0200120
Gilles Peskine449bd832023-01-11 14:50:10 +0100121 return (int) len;
Paul Bakker9852d002013-08-26 17:56:37 +0200122}
123
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200124#if defined(MBEDTLS_BIGNUM_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100125int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start, const mbedtls_mpi *X)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000126{
Janos Follath24eed8d2019-11-22 13:21:35 +0000127 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000128 size_t len = 0;
129
130 // Write the MPI
131 //
Gilles Peskine449bd832023-01-11 14:50:10 +0100132 len = mbedtls_mpi_size(X);
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000133
Gilles Peskine321a0892022-06-10 20:13:33 +0200134 /* DER represents 0 with a sign bit (0=nonnegative) and 7 value bits, not
135 * as 0 digits. We need to end up with 020100, not with 0200. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100136 if (len == 0) {
Gilles Peskine321a0892022-06-10 20:13:33 +0200137 len = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100138 }
Gilles Peskine321a0892022-06-10 20:13:33 +0200139
Gilles Peskine449bd832023-01-11 14:50:10 +0100140 if (*p < start || (size_t) (*p - start) < len) {
141 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
142 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000143
144 (*p) -= len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100145 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(X, *p, len));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000146
147 // DER format assumes 2s complement for numbers, so the leftmost bit
148 // should be 0 for positive numbers and 1 for negative numbers.
149 //
Gilles Peskine449bd832023-01-11 14:50:10 +0100150 if (X->s == 1 && **p & 0x80) {
151 if (*p - start < 1) {
152 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
153 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000154
155 *--(*p) = 0x00;
156 len += 1;
157 }
158
Gilles Peskine449bd832023-01-11 14:50:10 +0100159 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
160 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_INTEGER));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000161
Paul Bakker3d8fb632014-04-17 12:42:41 +0200162 ret = (int) len;
163
164cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +0100165 return ret;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000166}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200167#endif /* MBEDTLS_BIGNUM_C */
Paul Bakkered27a042013-04-18 22:46:23 +0200168
Gilles Peskine449bd832023-01-11 14:50:10 +0100169int mbedtls_asn1_write_null(unsigned char **p, const unsigned char *start)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000170{
Janos Follath24eed8d2019-11-22 13:21:35 +0000171 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000172 size_t len = 0;
173
174 // Write NULL
175 //
Gilles Peskine449bd832023-01-11 14:50:10 +0100176 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, 0));
177 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_NULL));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000178
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 return (int) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000180}
181
Gilles Peskine449bd832023-01-11 14:50:10 +0100182int mbedtls_asn1_write_oid(unsigned char **p, const unsigned char *start,
183 const char *oid, size_t oid_len)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000184{
Janos Follath24eed8d2019-11-22 13:21:35 +0000185 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000186 size_t len = 0;
187
Gilles Peskine449bd832023-01-11 14:50:10 +0100188 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
189 (const unsigned char *) oid, oid_len));
190 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
191 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OID));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000192
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 return (int) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000194}
195
Gilles Peskine449bd832023-01-11 14:50:10 +0100196int mbedtls_asn1_write_algorithm_identifier(unsigned char **p, const unsigned char *start,
197 const char *oid, size_t oid_len,
198 size_t par_len)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000199{
Jethro Beekman01672442023-04-19 14:08:14 +0200200 return mbedtls_asn1_write_algorithm_identifier_ext(p, start, oid, oid_len, par_len, 1);
201}
202
203int mbedtls_asn1_write_algorithm_identifier_ext(unsigned char **p, const unsigned char *start,
204 const char *oid, size_t oid_len,
205 size_t par_len, int has_par)
206{
Janos Follath24eed8d2019-11-22 13:21:35 +0000207 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000208 size_t len = 0;
209
Jethro Beekman01672442023-04-19 14:08:14 +0200210 if (has_par) {
211 if (par_len == 0) {
212 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_null(p, start));
213 } else {
214 len += par_len;
215 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000217
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000219
Gilles Peskine449bd832023-01-11 14:50:10 +0100220 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
221 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start,
222 MBEDTLS_ASN1_CONSTRUCTED |
223 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000224
Gilles Peskine449bd832023-01-11 14:50:10 +0100225 return (int) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000226}
227
Gilles Peskine449bd832023-01-11 14:50:10 +0100228int mbedtls_asn1_write_bool(unsigned char **p, const unsigned char *start, int boolean)
Paul Bakker329def32013-09-06 16:34:38 +0200229{
Janos Follath24eed8d2019-11-22 13:21:35 +0000230 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker329def32013-09-06 16:34:38 +0200231 size_t len = 0;
232
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 if (*p - start < 1) {
234 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
235 }
Paul Bakker329def32013-09-06 16:34:38 +0200236
Jonathan Leroy87c96c22015-10-14 09:41:56 +0200237 *--(*p) = (boolean) ? 255 : 0;
Paul Bakker329def32013-09-06 16:34:38 +0200238 len++;
239
Gilles Peskine449bd832023-01-11 14:50:10 +0100240 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
241 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_BOOLEAN));
Paul Bakker329def32013-09-06 16:34:38 +0200242
Gilles Peskine449bd832023-01-11 14:50:10 +0100243 return (int) len;
Paul Bakker329def32013-09-06 16:34:38 +0200244}
245
Gilles Peskine449bd832023-01-11 14:50:10 +0100246static int asn1_write_tagged_int(unsigned char **p, const unsigned char *start, int val, int tag)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000247{
Janos Follath24eed8d2019-11-22 13:21:35 +0000248 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000249 size_t len = 0;
250
Gilles Peskine449bd832023-01-11 14:50:10 +0100251 do {
252 if (*p - start < 1) {
253 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
254 }
Gilles Peskine1dbab672019-03-01 18:15:18 +0100255 len += 1;
256 *--(*p) = val & 0xff;
257 val >>= 8;
Gilles Peskine449bd832023-01-11 14:50:10 +0100258 } while (val > 0);
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000259
Gilles Peskine449bd832023-01-11 14:50:10 +0100260 if (**p & 0x80) {
261 if (*p - start < 1) {
262 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
263 }
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000264 *--(*p) = 0x00;
265 len += 1;
266 }
267
Gilles Peskine449bd832023-01-11 14:50:10 +0100268 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
269 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000270
Gilles Peskine449bd832023-01-11 14:50:10 +0100271 return (int) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000272}
273
Gilles Peskine449bd832023-01-11 14:50:10 +0100274int mbedtls_asn1_write_int(unsigned char **p, const unsigned char *start, int val)
Mykhailo Sopiha20180ca2019-10-29 15:58:10 +0200275{
Gilles Peskine449bd832023-01-11 14:50:10 +0100276 return asn1_write_tagged_int(p, start, val, MBEDTLS_ASN1_INTEGER);
Mykhailo Sopiha20180ca2019-10-29 15:58:10 +0200277}
278
Gilles Peskine449bd832023-01-11 14:50:10 +0100279int mbedtls_asn1_write_enum(unsigned char **p, const unsigned char *start, int val)
Mykhailo Sopiha20180ca2019-10-29 15:58:10 +0200280{
Gilles Peskine449bd832023-01-11 14:50:10 +0100281 return asn1_write_tagged_int(p, start, val, MBEDTLS_ASN1_ENUMERATED);
Mykhailo Sopiha20180ca2019-10-29 15:58:10 +0200282}
283
Gilles Peskine449bd832023-01-11 14:50:10 +0100284int mbedtls_asn1_write_tagged_string(unsigned char **p, const unsigned char *start, int tag,
285 const char *text, size_t text_len)
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000286{
Janos Follath24eed8d2019-11-22 13:21:35 +0000287 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000288 size_t len = 0;
289
Gilles Peskine449bd832023-01-11 14:50:10 +0100290 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
291 (const unsigned char *) text,
292 text_len));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000293
Gilles Peskine449bd832023-01-11 14:50:10 +0100294 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
295 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, tag));
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000296
Gilles Peskine449bd832023-01-11 14:50:10 +0100297 return (int) len;
Paul Bakkerbdb912d2012-02-13 23:11:30 +0000298}
Paul Bakker598e4502013-08-25 14:46:39 +0200299
Gilles Peskine449bd832023-01-11 14:50:10 +0100300int mbedtls_asn1_write_utf8_string(unsigned char **p, const unsigned char *start,
301 const char *text, size_t text_len)
Jaeden Amero23f954d2018-05-17 11:46:13 +0100302{
Gilles Peskine449bd832023-01-11 14:50:10 +0100303 return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len);
Jaeden Amero23f954d2018-05-17 11:46:13 +0100304}
305
Gilles Peskine449bd832023-01-11 14:50:10 +0100306int mbedtls_asn1_write_printable_string(unsigned char **p, const unsigned char *start,
307 const char *text, size_t text_len)
Jaeden Amero23f954d2018-05-17 11:46:13 +0100308{
Gilles Peskine449bd832023-01-11 14:50:10 +0100309 return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text,
310 text_len);
Jaeden Amero23f954d2018-05-17 11:46:13 +0100311}
312
Gilles Peskine449bd832023-01-11 14:50:10 +0100313int mbedtls_asn1_write_ia5_string(unsigned char **p, const unsigned char *start,
314 const char *text, size_t text_len)
Paul Bakker05888152012-02-16 10:26:57 +0000315{
Gilles Peskine449bd832023-01-11 14:50:10 +0100316 return mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len);
Paul Bakker05888152012-02-16 10:26:57 +0000317}
Paul Bakker598e4502013-08-25 14:46:39 +0200318
Gilles Peskine449bd832023-01-11 14:50:10 +0100319int mbedtls_asn1_write_named_bitstring(unsigned char **p,
320 const unsigned char *start,
321 const unsigned char *buf,
322 size_t bits)
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100323{
324 size_t unused_bits, byte_len;
325 const unsigned char *cur_byte;
326 unsigned char cur_byte_shifted;
327 unsigned char bit;
328
Gilles Peskine449bd832023-01-11 14:50:10 +0100329 byte_len = (bits + 7) / 8;
330 unused_bits = (byte_len * 8) - bits;
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100331
332 /*
333 * Named bitstrings require that trailing 0s are excluded in the encoding
334 * of the bitstring. Trailing 0s are considered part of the 'unused' bits
335 * when encoding this value in the first content octet
336 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100337 if (bits != 0) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100338 cur_byte = buf + byte_len - 1;
339 cur_byte_shifted = *cur_byte >> unused_bits;
340
Gilles Peskine449bd832023-01-11 14:50:10 +0100341 for (;;) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100342 bit = cur_byte_shifted & 0x1;
343 cur_byte_shifted >>= 1;
344
Gilles Peskine449bd832023-01-11 14:50:10 +0100345 if (bit != 0) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100346 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100347 }
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100348
349 bits--;
Gilles Peskine449bd832023-01-11 14:50:10 +0100350 if (bits == 0) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100351 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100352 }
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100353
Gilles Peskine449bd832023-01-11 14:50:10 +0100354 if (bits % 8 == 0) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100355 cur_byte_shifted = *--cur_byte;
Gilles Peskine449bd832023-01-11 14:50:10 +0100356 }
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100357 }
358 }
359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 return mbedtls_asn1_write_bitstring(p, start, buf, bits);
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100361}
362
Gilles Peskine449bd832023-01-11 14:50:10 +0100363int mbedtls_asn1_write_bitstring(unsigned char **p, const unsigned char *start,
364 const unsigned char *buf, size_t bits)
Paul Bakker598e4502013-08-25 14:46:39 +0200365{
Janos Follath24eed8d2019-11-22 13:21:35 +0000366 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100367 size_t len = 0;
368 size_t unused_bits, byte_len;
Paul Bakker598e4502013-08-25 14:46:39 +0200369
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 byte_len = (bits + 7) / 8;
371 unused_bits = (byte_len * 8) - bits;
Paul Bakker598e4502013-08-25 14:46:39 +0200372
Gilles Peskine449bd832023-01-11 14:50:10 +0100373 if (*p < start || (size_t) (*p - start) < byte_len + 1) {
374 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
375 }
Paul Bakker598e4502013-08-25 14:46:39 +0200376
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100377 len = byte_len + 1;
Paul Bakker598e4502013-08-25 14:46:39 +0200378
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100379 /* Write the bitstring. Ensure the unused bits are zeroed */
Gilles Peskine449bd832023-01-11 14:50:10 +0100380 if (byte_len > 0) {
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100381 byte_len--;
Gilles Peskine449bd832023-01-11 14:50:10 +0100382 *--(*p) = buf[byte_len] & ~((0x1 << unused_bits) - 1);
383 (*p) -= byte_len;
384 memcpy(*p, buf, byte_len);
Andres Amaya Garciaec6329f2018-09-26 10:48:24 +0100385 }
386
387 /* Write unused bits */
Gilles Peskine449bd832023-01-11 14:50:10 +0100388 *--(*p) = (unsigned char) unused_bits;
Paul Bakker598e4502013-08-25 14:46:39 +0200389
Gilles Peskine449bd832023-01-11 14:50:10 +0100390 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
391 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_BIT_STRING));
Paul Bakker598e4502013-08-25 14:46:39 +0200392
Gilles Peskine449bd832023-01-11 14:50:10 +0100393 return (int) len;
Paul Bakker598e4502013-08-25 14:46:39 +0200394}
395
Gilles Peskine449bd832023-01-11 14:50:10 +0100396int mbedtls_asn1_write_octet_string(unsigned char **p, const unsigned char *start,
397 const unsigned char *buf, size_t size)
Paul Bakker598e4502013-08-25 14:46:39 +0200398{
Janos Follath24eed8d2019-11-22 13:21:35 +0000399 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker598e4502013-08-25 14:46:39 +0200400 size_t len = 0;
401
Gilles Peskine449bd832023-01-11 14:50:10 +0100402 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start, buf, size));
Paul Bakker598e4502013-08-25 14:46:39 +0200403
Gilles Peskine449bd832023-01-11 14:50:10 +0100404 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
405 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OCTET_STRING));
Paul Bakker598e4502013-08-25 14:46:39 +0200406
Gilles Peskine449bd832023-01-11 14:50:10 +0100407 return (int) len;
Paul Bakker598e4502013-08-25 14:46:39 +0200408}
Paul Bakker59ba59f2013-09-09 11:26:00 +0200409
Hanno Becker44da18a2018-10-12 10:42:13 +0100410
411/* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
412 * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
413static mbedtls_asn1_named_data *asn1_find_named_data(
Gilles Peskine449bd832023-01-11 14:50:10 +0100414 mbedtls_asn1_named_data *list,
415 const char *oid, size_t len)
Hanno Becker44da18a2018-10-12 10:42:13 +0100416{
Gilles Peskine449bd832023-01-11 14:50:10 +0100417 while (list != NULL) {
418 if (list->oid.len == len &&
419 memcmp(list->oid.p, oid, len) == 0) {
Hanno Becker44da18a2018-10-12 10:42:13 +0100420 break;
421 }
422
423 list = list->next;
424 }
425
Gilles Peskine449bd832023-01-11 14:50:10 +0100426 return list;
Hanno Becker44da18a2018-10-12 10:42:13 +0100427}
428
429mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
Gilles Peskine449bd832023-01-11 14:50:10 +0100430 mbedtls_asn1_named_data **head,
431 const char *oid, size_t oid_len,
432 const unsigned char *val,
433 size_t val_len)
Paul Bakker59ba59f2013-09-09 11:26:00 +0200434{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200435 mbedtls_asn1_named_data *cur;
Paul Bakker59ba59f2013-09-09 11:26:00 +0200436
Gilles Peskine449bd832023-01-11 14:50:10 +0100437 if ((cur = asn1_find_named_data(*head, oid, oid_len)) == NULL) {
Paul Bakker59ba59f2013-09-09 11:26:00 +0200438 // Add new entry if not present yet based on OID
439 //
Gilles Peskine449bd832023-01-11 14:50:10 +0100440 cur = (mbedtls_asn1_named_data *) mbedtls_calloc(1,
441 sizeof(mbedtls_asn1_named_data));
442 if (cur == NULL) {
443 return NULL;
Paul Bakker59ba59f2013-09-09 11:26:00 +0200444 }
445
Gilles Peskine449bd832023-01-11 14:50:10 +0100446 cur->oid.len = oid_len;
447 cur->oid.p = mbedtls_calloc(1, oid_len);
448 if (cur->oid.p == NULL) {
449 mbedtls_free(cur);
450 return NULL;
451 }
452
453 memcpy(cur->oid.p, oid, oid_len);
Manuel Pégourié-Gonnarde5b0fc12014-11-12 22:27:42 +0100454
Paul Bakker59ba59f2013-09-09 11:26:00 +0200455 cur->val.len = val_len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100456 if (val_len != 0) {
457 cur->val.p = mbedtls_calloc(1, val_len);
458 if (cur->val.p == NULL) {
459 mbedtls_free(cur->oid.p);
460 mbedtls_free(cur);
461 return NULL;
Gilles Peskine09c0a232019-03-04 15:00:06 +0100462 }
Paul Bakker59ba59f2013-09-09 11:26:00 +0200463 }
464
Paul Bakker59ba59f2013-09-09 11:26:00 +0200465 cur->next = *head;
466 *head = cur;
Gilles Peskine449bd832023-01-11 14:50:10 +0100467 } else if (val_len == 0) {
468 mbedtls_free(cur->val.p);
Gilles Peskine09c0a232019-03-04 15:00:06 +0100469 cur->val.p = NULL;
Gilles Peskine449bd832023-01-11 14:50:10 +0100470 } else if (cur->val.len != val_len) {
Manuel Pégourié-Gonnard97b52092015-12-10 10:50:51 +0100471 /*
472 * Enlarge existing value buffer if needed
473 * Preserve old data until the allocation succeeded, to leave list in
474 * a consistent state in case allocation fails.
475 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100476 void *p = mbedtls_calloc(1, val_len);
477 if (p == NULL) {
478 return NULL;
479 }
Manuel Pégourié-Gonnard97b52092015-12-10 10:50:51 +0100480
Gilles Peskine449bd832023-01-11 14:50:10 +0100481 mbedtls_free(cur->val.p);
Manuel Pégourié-Gonnard97b52092015-12-10 10:50:51 +0100482 cur->val.p = p;
483 cur->val.len = val_len;
Paul Bakker59ba59f2013-09-09 11:26:00 +0200484 }
485
Gilles Peskine449bd832023-01-11 14:50:10 +0100486 if (val != NULL && val_len != 0) {
487 memcpy(cur->val.p, val, val_len);
488 }
Paul Bakker59ba59f2013-09-09 11:26:00 +0200489
Gilles Peskine449bd832023-01-11 14:50:10 +0100490 return cur;
Paul Bakker59ba59f2013-09-09 11:26:00 +0200491}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200492#endif /* MBEDTLS_ASN1_WRITE_C */