From: jsing Date: Wed, 2 Mar 2022 11:28:00 +0000 (+0000) Subject: Rewrite ASN1_OBJECT content to ascii/text conversion. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=09967094a1adca610891d1268a89a074775ea993;p=openbsd Rewrite ASN1_OBJECT content to ascii/text conversion. Rewrite the ASN1_OBJECT content to ascii/text conversion code using CBB and CBS. Currently there is a strange split with i2t_ASN1_OBJECT() calling OBJ_obj2txt() which implements the conversion, while OBJ_txt2obj() calls back into the misnamed a2d_ASN1_OBJECT() function. Move the conversion code into asn1/a_object.c and have OBJ_txt2obj() call that instead. ok inoguchi@ tb@ --- diff --git a/lib/libcrypto/asn1/a_object.c b/lib/libcrypto/asn1/a_object.c index 1407f7df1cd..f26026e6aa7 100644 --- a/lib/libcrypto/asn1/a_object.c +++ b/lib/libcrypto/asn1/a_object.c @@ -1,4 +1,4 @@ -/* $OpenBSD: a_object.c,v 1.37 2022/01/07 11:13:54 tb Exp $ */ +/* $OpenBSD: a_object.c,v 1.38 2022/03/02 11:28:00 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -270,37 +270,190 @@ a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) return (0); } +static int +oid_parse_arc(CBS *cbs, uint64_t *out_arc) +{ + uint64_t arc = 0; + uint8_t val; + + do { + if (!CBS_get_u8(cbs, &val)) + return 0; + if (arc == 0 && val == 0x80) + return 0; + if (arc > (UINT64_MAX >> 7)) + return 0; + arc = (arc << 7) | (val & 0x7f); + } while (val & 0x80); + + *out_arc = arc; + + return 1; +} + +static int +oid_add_arc_txt(CBB *cbb, uint64_t arc, int first) +{ + const char *fmt = ".%llu"; + char s[22]; /* Digits in decimal representation of 2^64-1, plus '.' and NUL. */ + int n; + + if (first) + fmt = "%llu"; + n = snprintf(s, sizeof(s), fmt, (unsigned long long)arc); + if (n < 0 || (size_t)n >= sizeof(s)) + return 0; + if (!CBB_add_bytes(cbb, s, n)) + return 0; + + return 1; +} + +static int +c2a_ASN1_OBJECT(CBS *cbs, CBB *cbb) +{ + uint64_t arc, si1, si2; + + /* + * X.690 section 8.19 - the first two subidentifiers are encoded as + * (x * 40) + y, with x being limited to [0,1,2]. + */ + if (!oid_parse_arc(cbs, &arc)) + return 0; + if ((si1 = arc / 40) > 2) + si1 = 2; + si2 = arc - si1 * 40; + + if (!oid_add_arc_txt(cbb, si1, 1)) + return 0; + if (!oid_add_arc_txt(cbb, si2, 0)) + return 0; + + while (CBS_len(cbs) > 0) { + if (!oid_parse_arc(cbs, &arc)) + return 0; + if (!oid_add_arc_txt(cbb, arc, 0)) + return 0; + } + + /* NUL terminate. */ + if (!CBB_add_u8(cbb, 0)) + return 0; + + return 1; +} + +static int +i2t_ASN1_OBJECT_oid(const ASN1_OBJECT *aobj, CBB *cbb) +{ + CBS cbs; + + CBS_init(&cbs, aobj->data, aobj->length); + + return c2a_ASN1_OBJECT(&cbs, cbb); +} + +static int +i2t_ASN1_OBJECT_name(const ASN1_OBJECT *aobj, CBB *cbb, const char **out_name) +{ + const char *name; + int nid; + + if ((nid = OBJ_obj2nid(aobj)) == NID_undef) + return 0; + + if ((name = OBJ_nid2ln(nid)) == NULL) + name = OBJ_nid2sn(nid); + if (name == NULL) + return 0; + + *out_name = name; + + if (!CBB_add_bytes(cbb, name, strlen(name))) + return 0; + + /* NUL terminate. */ + if (!CBB_add_u8(cbb, 0)) + return 0; + + return 1; +} + +static int +i2t_ASN1_OBJECT_cbb(const ASN1_OBJECT *aobj, CBB *cbb, int no_name) +{ + const char *name; + + if (!no_name) { + if (i2t_ASN1_OBJECT_name(aobj, cbb, &name)) + return 1; + if (name != NULL) + return 0; + } + return i2t_ASN1_OBJECT_oid(aobj, cbb); +} + +int +i2t_ASN1_OBJECT_internal(const ASN1_OBJECT *aobj, char *buf, int buf_len, int no_name) +{ + uint8_t *data = NULL; + size_t data_len; + CBB cbb; + int ret = 0; + + if (buf_len < 0) + return 0; + if (buf_len > 0) + buf[0] = '\0'; + + if (!CBB_init(&cbb, 0)) + goto err; + if (!i2t_ASN1_OBJECT_cbb(aobj, &cbb, no_name)) + goto err; + if (!CBB_finish(&cbb, &data, &data_len)) + goto err; + + ret = strlcpy(buf, data, buf_len); + err: + CBB_cleanup(&cbb); + free(data); + + return ret; +} + int -i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a) +i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *aobj) { - return OBJ_obj2txt(buf, buf_len, a, 0); + return i2t_ASN1_OBJECT_internal(aobj, buf, buf_len, 0); } int -i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a) +i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *aobj) { - char *tmp = NULL; - size_t tlen = 256; - int i = -1; + uint8_t *data = NULL; + size_t data_len; + CBB cbb; + int ret = -1; - if ((a == NULL) || (a->data == NULL)) - return(BIO_write(bp, "NULL", 4)); - if ((tmp = malloc(tlen)) == NULL) - return -1; - i = i2t_ASN1_OBJECT(tmp, tlen, a); - if (i > (int)(tlen - 1)) { - freezero(tmp, tlen); - if ((tmp = malloc(i + 1)) == NULL) - return -1; - tlen = i + 1; - i = i2t_ASN1_OBJECT(tmp, tlen, a); + if (aobj == NULL || aobj->data == NULL) + return BIO_write(bp, "NULL", 4); + + if (!CBB_init(&cbb, 0)) + goto err; + if (!i2t_ASN1_OBJECT_cbb(aobj, &cbb, 0)) { + ret = BIO_write(bp, "", 9); + goto err; } - if (i <= 0) - i = BIO_write(bp, "", 9); - else - i = BIO_write(bp, tmp, i); - freezero(tmp, tlen); - return (i); + if (!CBB_finish(&cbb, &data, &data_len)) + goto err; + + ret = BIO_write(bp, data, data_len); + + err: + CBB_cleanup(&cbb); + free(data); + + return ret; } ASN1_OBJECT * diff --git a/lib/libcrypto/asn1/asn1_locl.h b/lib/libcrypto/asn1/asn1_locl.h index 7d34d7c17a1..bb6a9fc91ae 100644 --- a/lib/libcrypto/asn1/asn1_locl.h +++ b/lib/libcrypto/asn1/asn1_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: asn1_locl.h,v 1.20 2022/01/14 08:53:53 tb Exp $ */ +/* $OpenBSD: asn1_locl.h,v 1.21 2022/03/02 11:28:00 jsing Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -201,4 +201,7 @@ int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class, int asn1_tag2charwidth(int tag); +int i2t_ASN1_OBJECT_internal(const ASN1_OBJECT *aobj, char *buf, int buf_len, + int no_name); + __END_HIDDEN_DECLS diff --git a/lib/libcrypto/objects/obj_dat.c b/lib/libcrypto/objects/obj_dat.c index 03e65f1dfeb..786bed6c7ab 100644 --- a/lib/libcrypto/objects/obj_dat.c +++ b/lib/libcrypto/objects/obj_dat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: obj_dat.c,v 1.47 2022/02/12 03:01:59 jsing Exp $ */ +/* $OpenBSD: obj_dat.c,v 1.48 2022/03/02 11:28:00 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -524,83 +524,12 @@ OBJ_txt2obj(const char *s, int no_name) } int -OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name) +OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *aobj, int no_name) { - int i, ret = 0, len, nid, first = 1; - const unsigned char *p; - uint64_t l; - - /* Ensure that, at every state, |buf| is NUL-terminated. */ - if (buf_len > 0) - buf[0] = '\0'; - - if ((a == NULL) || (a->data == NULL)) - goto err; - - if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) { - const char *s; - s = OBJ_nid2ln(nid); - if (s == NULL) - s = OBJ_nid2sn(nid); - if (s) { - ret = strlcpy(buf, s, buf_len); - goto out; - } - } - - len = a->length; - p = a->data; - - while (len > 0) { - l = 0; - for (;;) { - unsigned char c = *p++; - len--; - if ((len == 0) && (c & 0x80)) - goto err; - l |= c & 0x7f; - if (!(c & 0x80)) - break; - if (l > (UINT64_MAX >> 7L)) - goto err; - l <<= 7L; - } - - if (first) { - first = 0; - if (l >= 80) { - i = 2; - l -= 80; - } else { - i = (int)(l / 40); - l -= (long)(i * 40); - } - if (buf_len > 1) { - *buf++ = i + '0'; - *buf = '\0'; - buf_len--; - } - ret++; - } - - i = snprintf(buf, buf_len, ".%llu", l); - if (i < 0) - goto err; - if (i >= buf_len) { - buf_len = 0; - } else { - buf += i; - buf_len -= i; - } - ret += i; - } - - out: - return ret; + if (aobj == NULL || aobj->data == NULL) + return 0; - err: - ret = 0; - goto out; + return i2t_ASN1_OBJECT_internal(aobj, buf, buf_len, no_name); } int