Skip to content

Commit 6845433

Browse files
author
jsing
committed
Rewrite ascii/text to ASN.1 object conversion.
Rewrite the ascii/text to ASN.1 object conversion code using CBB/CBS, while also addressing some of the bizarre behaviour (such as allowing mixed separators and treating '..' as a zero value). ok inoguchi@ tb@
1 parent 7b4b4dc commit 6845433

File tree

1 file changed

+167
-121
lines changed

1 file changed

+167
-121
lines changed

src/lib/libcrypto/asn1/a_object.c

Lines changed: 167 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: a_object.c,v 1.41 2022/03/15 18:47:22 jsing Exp $ */
1+
/* $OpenBSD: a_object.c,v 1.42 2022/03/19 17:35:52 jsing Exp $ */
22
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
33
* All rights reserved.
44
*
@@ -62,7 +62,6 @@
6262

6363
#include <openssl/asn1.h>
6464
#include <openssl/asn1t.h>
65-
#include <openssl/bn.h>
6665
#include <openssl/err.h>
6766
#include <openssl/buffer.h>
6867
#include <openssl/objects.h>
@@ -146,128 +145,25 @@ i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
146145
return (objsize);
147146
}
148147

149-
int
150-
a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
148+
static int
149+
oid_add_arc(CBB *cbb, uint64_t arc)
151150
{
152-
int i, first, len = 0, c, use_bn;
153-
char ftmp[24], *tmp = ftmp;
154-
int tmpsize = sizeof ftmp;
155-
const char *p;
156-
unsigned long l;
157-
BIGNUM *bl = NULL;
158-
159-
if (num == 0)
160-
return (0);
161-
else if (num == -1)
162-
num = strlen(buf);
163-
164-
p = buf;
165-
c = *(p++);
166-
num--;
167-
if ((c >= '0') && (c <= '2')) {
168-
first= c-'0';
169-
} else {
170-
ASN1error(ASN1_R_FIRST_NUM_TOO_LARGE);
171-
goto err;
172-
}
173-
174-
if (num <= 0) {
175-
ASN1error(ASN1_R_MISSING_SECOND_NUMBER);
176-
goto err;
177-
}
178-
c = *(p++);
179-
num--;
180-
for (;;) {
181-
if (num <= 0)
182-
break;
183-
if ((c != '.') && (c != ' ')) {
184-
ASN1error(ASN1_R_INVALID_SEPARATOR);
185-
goto err;
186-
}
187-
l = 0;
188-
use_bn = 0;
189-
for (;;) {
190-
if (num <= 0)
191-
break;
192-
num--;
193-
c = *(p++);
194-
if ((c == ' ') || (c == '.'))
195-
break;
196-
if ((c < '0') || (c > '9')) {
197-
ASN1error(ASN1_R_INVALID_DIGIT);
198-
goto err;
199-
}
200-
if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
201-
use_bn = 1;
202-
if (!bl)
203-
bl = BN_new();
204-
if (!bl || !BN_set_word(bl, l))
205-
goto err;
206-
}
207-
if (use_bn) {
208-
if (!BN_mul_word(bl, 10L) ||
209-
!BN_add_word(bl, c-'0'))
210-
goto err;
211-
} else
212-
l = l * 10L + (long)(c - '0');
213-
}
214-
if (len == 0) {
215-
if ((first < 2) && (l >= 40)) {
216-
ASN1error(ASN1_R_SECOND_NUMBER_TOO_LARGE);
217-
goto err;
218-
}
219-
if (use_bn) {
220-
if (!BN_add_word(bl, first * 40))
221-
goto err;
222-
} else
223-
l += (long)first * 40;
224-
}
225-
i = 0;
226-
if (use_bn) {
227-
int blsize;
228-
blsize = BN_num_bits(bl);
229-
blsize = (blsize + 6) / 7;
230-
if (blsize > tmpsize) {
231-
if (tmp != ftmp)
232-
free(tmp);
233-
tmpsize = blsize + 32;
234-
tmp = malloc(tmpsize);
235-
if (!tmp)
236-
goto err;
237-
}
238-
while (blsize--)
239-
tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
240-
} else {
241-
242-
for (;;) {
243-
tmp[i++] = (unsigned char)l & 0x7f;
244-
l >>= 7L;
245-
if (l == 0L)
246-
break;
247-
}
248-
249-
}
250-
if (out != NULL) {
251-
if (len + i > olen) {
252-
ASN1error(ASN1_R_BUFFER_TOO_SMALL);
253-
goto err;
254-
}
255-
while (--i > 0)
256-
out[len++] = tmp[i]|0x80;
257-
out[len++] = tmp[0];
258-
} else
259-
len += i;
151+
int started = 0;
152+
uint8_t val;
153+
int i;
154+
155+
for (i = (sizeof(arc) * 8) / 7; i >= 0; i--) {
156+
val = (arc >> (i * 7)) & 0x7f;
157+
if (!started && i != 0 && val == 0)
158+
continue;
159+
if (i > 0)
160+
val |= 0x80;
161+
if (!CBB_add_u8(cbb, val))
162+
return 0;
163+
started = 1;
260164
}
261-
if (tmp != ftmp)
262-
free(tmp);
263-
BN_free(bl);
264-
return (len);
265165

266-
err:
267-
if (tmp != ftmp)
268-
free(tmp);
269-
BN_free(bl);
270-
return (0);
166+
return 1;
271167
}
272168

273169
static int
@@ -309,6 +205,111 @@ oid_add_arc_txt(CBB *cbb, uint64_t arc, int first)
309205
return 1;
310206
}
311207

208+
static int
209+
oid_parse_arc_txt(CBS *cbs, uint64_t *out_arc, char *separator, int first)
210+
{
211+
uint64_t arc = 0;
212+
int digits = 0;
213+
uint8_t val;
214+
215+
if (!first) {
216+
if (!CBS_get_u8(cbs, &val))
217+
return 0;
218+
if ((*separator == 0 && val != '.' && val != ' ') ||
219+
(*separator != 0 && val != *separator)) {
220+
ASN1error(ASN1_R_INVALID_SEPARATOR);
221+
return 0;
222+
}
223+
*separator = val;
224+
}
225+
226+
while (CBS_len(cbs) > 0) {
227+
if (!CBS_peek_u8(cbs, &val))
228+
return 0;
229+
if (val == '.' || val == ' ')
230+
break;
231+
232+
if (!CBS_get_u8(cbs, &val))
233+
return 0;
234+
if (val < '0' || val > '9') {
235+
/* For the first arc we treat this as the separator. */
236+
if (first) {
237+
ASN1error(ASN1_R_INVALID_SEPARATOR);
238+
return 0;
239+
}
240+
ASN1error(ASN1_R_INVALID_DIGIT);
241+
return 0;
242+
}
243+
val -= '0';
244+
245+
if (digits > 0 && arc == 0 && val == 0) {
246+
ASN1error(ASN1_R_INVALID_NUMBER);
247+
return 0;
248+
}
249+
digits++;
250+
251+
if (arc > UINT64_MAX / 10) {
252+
ASN1error(ASN1_R_TOO_LONG);
253+
return 0;
254+
}
255+
arc = arc * 10 + val;
256+
}
257+
258+
if (digits < 1) {
259+
ASN1error(ASN1_R_INVALID_NUMBER);
260+
return 0;
261+
}
262+
263+
*out_arc = arc;
264+
265+
return 1;
266+
}
267+
268+
static int
269+
a2c_ASN1_OBJECT_internal(CBB *cbb, CBS *cbs)
270+
{
271+
uint64_t arc, si1, si2;
272+
char separator = 0;
273+
274+
if (!oid_parse_arc_txt(cbs, &si1, &separator, 1))
275+
return 0;
276+
277+
if (CBS_len(cbs) == 0) {
278+
ASN1error(ASN1_R_MISSING_SECOND_NUMBER);
279+
return 0;
280+
}
281+
282+
if (!oid_parse_arc_txt(cbs, &si2, &separator, 0))
283+
return 0;
284+
285+
/*
286+
* X.690 section 8.19 - the first two subidentifiers are encoded as
287+
* (x * 40) + y, with x being limited to [0,1,2]. The second
288+
* subidentifier cannot exceed 39 for x < 2.
289+
*/
290+
if (si1 > 2) {
291+
ASN1error(ASN1_R_FIRST_NUM_TOO_LARGE);
292+
return 0;
293+
}
294+
if ((si1 < 2 && si2 >= 40) || si2 > UINT64_MAX - si1 * 40) {
295+
ASN1error(ASN1_R_SECOND_NUMBER_TOO_LARGE);
296+
return 0;
297+
}
298+
arc = si1 * 40 + si2;
299+
300+
if (!oid_add_arc(cbb, arc))
301+
return 0;
302+
303+
while (CBS_len(cbs) > 0) {
304+
if (!oid_parse_arc_txt(cbs, &arc, &separator, 0))
305+
return 0;
306+
if (!oid_add_arc(cbb, arc))
307+
return 0;
308+
}
309+
310+
return 1;
311+
}
312+
312313
static int
313314
c2a_ASN1_OBJECT(CBS *cbs, CBB *cbb)
314315
{
@@ -343,6 +344,51 @@ c2a_ASN1_OBJECT(CBS *cbs, CBB *cbb)
343344
return 1;
344345
}
345346

347+
int
348+
a2d_ASN1_OBJECT(unsigned char *out, int out_len, const char *in, int in_len)
349+
{
350+
uint8_t *data = NULL;
351+
size_t data_len;
352+
CBS cbs;
353+
CBB cbb;
354+
int ret = 0;
355+
356+
memset(&cbb, 0, sizeof(cbb));
357+
358+
if (in_len == -1)
359+
in_len = strlen(in);
360+
if (in_len <= 0)
361+
goto err;
362+
363+
CBS_init(&cbs, in, in_len);
364+
365+
if (!CBB_init(&cbb, 0))
366+
goto err;
367+
if (!a2c_ASN1_OBJECT_internal(&cbb, &cbs))
368+
goto err;
369+
if (!CBB_finish(&cbb, &data, &data_len))
370+
goto err;
371+
372+
if (data_len > INT_MAX)
373+
goto err;
374+
375+
if (out != NULL) {
376+
if (out_len <= 0 || (size_t)out_len < data_len) {
377+
ASN1error(ASN1_R_BUFFER_TOO_SMALL);
378+
goto err;
379+
}
380+
memcpy(out, data, data_len);
381+
}
382+
383+
ret = (int)data_len;
384+
385+
err:
386+
CBB_cleanup(&cbb);
387+
free(data);
388+
389+
return ret;
390+
}
391+
346392
static int
347393
i2t_ASN1_OBJECT_oid(const ASN1_OBJECT *aobj, CBB *cbb)
348394
{

0 commit comments

Comments
 (0)