/* Provenance: openssl/openssl OBJ_obj2txt (fixed). * repo: openssl/openssl * commit: d63b3e7959e79f98d60760a739f7876dc5adc838 * parent: 3ca28c9e81fae36b0b44dc39beecd2b5a7561975 * commit_url: https://github.com/openssl/openssl/commit/d63b3e7959e79f98d60760a739f7876dc5adc838 * cve: CVE-2023-2650 * license: Apache-2.0 * function: OBJ_obj2txt * relpath: crypto/objects/obj_dat.c */ int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name) { int i, n = 0, len, nid, first, use_bn; BIGNUM *bl; unsigned long l; const unsigned char *p; char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; const char *s; /* Ensure that, at every state, |buf| is NUL-terminated. */ if (buf != NULL && buf_len > 0) buf[0] = '\0'; if (a == NULL || a->data == NULL) return 0; if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) { s = OBJ_nid2ln(nid); if (s == NULL) s = OBJ_nid2sn(nid); if (s != NULL) { if (buf != NULL) OPENSSL_strlcpy(buf, s, buf_len); return (int)strlen(s); } } len = a->length; p = a->data; first = 1; bl = NULL; /* * RFC 2578 (STD 58) says this about OBJECT IDENTIFIERs: * * > 3.5. OBJECT IDENTIFIER values * > * > An OBJECT IDENTIFIER value is an ordered list of non-negative * > numbers. For the SMIv2, each number in the list is referred to as a * > sub-identifier, there are at most 128 sub-identifiers in a value, * > and each sub-identifier has a maximum value of 2^32-1 (4294967295 * > decimal). * * So a legitimate OID according to this RFC is at most (32 * 128 / 7), * i.e. 586 bytes long. * * Ref: https://datatracker.ietf.org/doc/html/rfc2578#section-3.5 */ if (len > 586) goto err; while (len > 0) { l = 0; use_bn = 0; for (;;) { unsigned char c = *p++; len--; if (len == 0 && (c & 0x80) != 0) goto err; if (use_bn) { if (!BN_add_word(bl, c & 0x7f)) goto err; } else { l |= c & 0x7f; } if ((c & 0x80) == 0) break; if (!use_bn && l > (ULONG_MAX >> 7L)) { if (bl == NULL && (bl = BN_new()) == NULL) goto err; if (!BN_set_word(bl, l)) goto err; use_bn = 1; } if (use_bn) { if (!BN_lshift(bl, bl, 7)) goto err; } else { l <<= 7L; } } if (first) { first = 0; if (l >= 80) { i = 2; if (use_bn) { if (!BN_sub_word(bl, 80)) goto err; } else { l -= 80; } } else { i = (int)(l / 40); l -= (long)(i * 40); } if (buf != NULL && buf_len > 1) { *buf++ = i + '0'; *buf = '\0'; buf_len--; } n++; } if (use_bn) { char *bndec; bndec = BN_bn2dec(bl); if (!bndec) goto err; i = strlen(bndec); if (buf != NULL) { if (buf_len > 1) { *buf++ = '.'; *buf = '\0'; buf_len--; } OPENSSL_strlcpy(buf, bndec, buf_len); if (i > buf_len) { buf += buf_len; buf_len = 0; } else { buf += i; buf_len -= i; } } n++; n += i; OPENSSL_free(bndec); } else { BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); i = strlen(tbuf); if (buf && buf_len > 0) { OPENSSL_strlcpy(buf, tbuf, buf_len); if (i > buf_len) { buf += buf_len; buf_len = 0; } else { buf += i; buf_len -= i; } } n += i; l = 0; } } BN_free(bl); return n; err: BN_free(bl); return -1; }