Merge 17d280195a09717f6ac5ce86bf8905ff1a0b4366 into 03e1438089654fb884ac48e0f3cd0049cfe2c102

This commit is contained in:
Ankit Kumar 2026-10-27 10:46:03 -04:00 committed by GitHub
commit 39ccb0e9b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 139 additions and 25 deletions

View File

@ -0,0 +1,3 @@
Bugfix
* In mbedtls_oid_get_numeric_string(), allow OID subidentifiers wider
than 32 bits instead of rejecting them as invalid ASN.1 data. Fixes #11001.

View File

@ -815,6 +815,77 @@ static char nibble_to_hex_digit(int i)
return (i < 10) ? (i + '0') : (i - 10 + 'A');
}
#define OID_MAX_SUBID_LEN 64
/* Convert a base-128 encoded OID subidentifier to decimal digits.
* If subtract > 0, subtract it first (used for the first subidentifier where
* value >= 80: value = 2 * 40 + c2 => c2 = value - 80).
* Returns the number of characters written on success, or a negative error code. */
static int oid_subid_to_dec(char *buf, size_t size,
const unsigned char *subid, size_t len,
unsigned int subtract)
{
unsigned char digits[OID_MAX_SUBID_LEN];
char dec_buf[OID_MAX_SUBID_LEN * 3];
size_t dec_count = 0;
size_t start = 0;
if (len > OID_MAX_SUBID_LEN) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
for (size_t i = 0; i < len; i++) {
digits[i] = subid[i] & 0x7F;
}
if (subtract > 0) {
unsigned int borrow = subtract;
for (size_t i = len; i > 0; i--) {
if (digits[i - 1] >= borrow) {
digits[i - 1] -= (unsigned char) borrow;
borrow = 0;
break;
} else {
digits[i - 1] = (unsigned char) (digits[i - 1] + 128 - borrow);
borrow = 1;
}
}
}
while (start < len && digits[start] == 0) {
start++;
}
if (start == len) {
dec_buf[dec_count++] = '0';
} else {
while (start < len) {
unsigned int rem = 0;
for (size_t i = start; i < len; i++) {
unsigned int cur = (rem << 7) | digits[i];
digits[i] = (unsigned char) (cur / 10);
rem = cur % 10;
}
dec_buf[dec_count++] = (char) ('0' + rem);
while (start < len && digits[start] == 0) {
start++;
}
}
}
/* Check if buf can hold the digits plus null terminator */
if (dec_count >= size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
for (size_t i = 0; i < dec_count; i++) {
buf[i] = dec_buf[dec_count - 1 - i];
}
buf[dec_count] = '\0';
return (int) dec_count;
}
/* Return the x.y.z.... style numeric string for the given OID */
int mbedtls_oid_get_numeric_string(char *buf, size_t size,
const mbedtls_asn1_buf *oid)
@ -822,7 +893,7 @@ int mbedtls_oid_get_numeric_string(char *buf, size_t size,
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
char *p = buf;
size_t n = size;
unsigned int value = 0;
size_t i = 0;
if (size > INT_MAX) {
/* Avoid overflow computing return value */
@ -834,22 +905,41 @@ int mbedtls_oid_get_numeric_string(char *buf, size_t size,
return MBEDTLS_ERR_ASN1_OUT_OF_DATA;
}
for (size_t i = 0; i < oid->len; i++) {
/* Prevent overflow in value. */
if (value > (UINT_MAX >> 7)) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
if ((value == 0) && ((oid->p[i]) == 0x80)) {
/* Overlong encoding is not allowed */
while (i < oid->len) {
size_t subid_start = i;
size_t subid_len;
unsigned int value = 0;
int overflow = 0;
int is_first = (n == size);
/* Overlong encoding is not allowed */
if (oid->p[subid_start] == 0x80) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
value <<= 7;
value |= oid->p[i] & 0x7F;
while (i < oid->len && (oid->p[i] & 0x80) != 0) {
i++;
}
if (!(oid->p[i] & 0x80)) {
/* Last byte */
if (n == size) {
if (i == oid->len) {
/* Unterminated subidentifier */
return MBEDTLS_ERR_ASN1_OUT_OF_DATA;
}
subid_len = i - subid_start + 1;
i++;
/* Try computing value in unsigned int (fast path) */
for (size_t j = subid_start; j < subid_start + subid_len; j++) {
if (value > (UINT_MAX >> 7)) {
overflow = 1;
break;
}
value = (value << 7) | (oid->p[j] & 0x7F);
}
if (!overflow) {
if (is_first) {
int component1;
unsigned int component2;
/* First subidentifier contains first two OID components */
@ -872,14 +962,30 @@ int mbedtls_oid_get_numeric_string(char *buf, size_t size,
}
n -= (size_t) ret;
p += ret;
value = 0;
} else {
size_t prefix_len = is_first ? 2 : 1;
if (n <= prefix_len) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
if (is_first) {
*p++ = '2';
*p++ = '.';
} else {
*p++ = '.';
}
n -= prefix_len;
ret = oid_subid_to_dec(p, n, &oid->p[subid_start], subid_len,
is_first ? 80 : 0);
if (ret < 0) {
return ret;
}
p += ret;
n -= (size_t) ret;
}
}
if (value != 0) {
/* Unterminated subidentifier */
return MBEDTLS_ERR_ASN1_OUT_OF_DATA;
}
*p = '\0';
return (int) (size - n);
}

View File

@ -2789,8 +2789,8 @@ x509_oid_numstr:"2b06010505070301":"1.3.6.1.5.5.7.3.1":17:PSA_ERROR_BUFFER_TOO_S
X509 OID numstring #4 (larger number)
x509_oid_numstr:"2a864886f70d":"1.2.840.113549":15:14
X509 OID numstring #5 (arithmetic overflow)
x509_oid_numstr:"2a8648f9f8f7f6f5f4f3f2f1f001":"":100:MBEDTLS_ERR_ASN1_INVALID_DATA
X509 OID numstring #5 (subidentifier > 32 bits)
x509_oid_numstr:"2a8648f9f8f7f6f5f4f3f2f1f001":"1.2.840.143967032551602640418817":100:32
X509 CRT keyUsage #1 (no extension, expected KU)
depends_on:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY:PSA_WANT_ALG_SHA_1
@ -3547,15 +3547,20 @@ oid_get_numeric_string:"50":0:"2.0"
OID get numeric string - 1 byte first subidentifier beyond 2.39
oid_get_numeric_string:"7f":0:"2.47"
# Encodes the number 0x0400000000 as a subidentifier which overflows 32-bits
OID get numeric string - 32-bit overflow
oid_get_numeric_string:"C080808000":MBEDTLS_ERR_ASN1_INVALID_DATA:""
# Encodes the number 0x0400000000 (17179869184) as a subidentifier (> 32 bits)
OID get numeric string - subidentifier > 32-bit first component
oid_get_numeric_string:"C080808000":0:"2.17179869104"
OID get numeric string - 32-bit overflow, second subidentifier
oid_get_numeric_string:"2BC080808000":MBEDTLS_ERR_ASN1_INVALID_DATA:""
OID get numeric string - subidentifier > 32-bit second component
oid_get_numeric_string:"2BC080808000":0:"1.3.17179869184"
# ITU-T X.667 clause 8 UUID arc: 2.25.329800735698586629295641978511506172918
OID get numeric string - 128-bit UUID subidentifier (X.667)
oid_get_numeric_string:"6983F09DA7EBCFDEE0C7A1A7B2C0948CC8F9D776":0:"2.25.329800735698586629295641978511506172918"
OID get numeric string - overlong encoding
oid_get_numeric_string:"8001":MBEDTLS_ERR_ASN1_INVALID_DATA:""
OID get numeric string - overlong encoding, second subidentifier
oid_get_numeric_string:"2B8001":MBEDTLS_ERR_ASN1_INVALID_DATA:""