Skip to content

Commit 23c9821

Browse files
committed
simplify encode OID and catch parse errors
so that when the OID string is not an OID string, it fails rather than encoding "something"
1 parent 92d755a commit 23c9821

File tree

1 file changed

+50
-74
lines changed

1 file changed

+50
-74
lines changed

src/protocols/der/encode.c

Lines changed: 50 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,11 @@ static ssize_t fr_der_encode_null(UNUSED fr_dbuff_t *dbuff, fr_dcursor_t *cursor
453453
static ssize_t fr_der_encode_oid_to_str(fr_dbuff_t *dbuff, const char *oid_str)
454454
{
455455
fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
456-
char buffer[21] = { 0 };
457-
uint64_t subidentifier = 0;
458-
uint8_t first_component = 0;
459-
size_t buffer_len = 0;
460-
size_t index = 0, bit_index;
461-
bool started_subidentifier = false, subsequent = false;
456+
bool first = true;
457+
uint8_t first_component;
458+
unsigned long long oid;
459+
char const *start = oid_str;
460+
char *end = NULL;
462461

463462
/*
464463
* The first subidentifier is the encoding of the first two object identifier components, encoded as:
@@ -467,84 +466,61 @@ static ssize_t fr_der_encode_oid_to_str(fr_dbuff_t *dbuff, const char *oid_str)
467466
* The first number is 0, 1, or 2.
468467
*/
469468

470-
first_component = (uint8_t)(strtol(&oid_str[0], NULL, 10));
471-
472-
index += 2; /* Advance past the first number and the delimiter '.' */
473-
474-
for (; index < strlen(oid_str) + 1; index++) {
475-
uint8_t byte = 0;
476-
477-
if (oid_str[index] == '.' || oid_str[index] == '\0') {
478-
/*
479-
* We have a subidentifier
480-
*/
481-
started_subidentifier = false;
482-
bit_index = sizeof(subidentifier) * 8;
483-
484-
if (buffer_len == 0) {
485-
fr_strerror_const("Empty buffer for final subidentifier");
486-
return -1;
487-
}
488-
489-
if (!subsequent) {
490-
subidentifier = (first_component * 40) + (uint64_t)strtol(buffer, NULL, 10);
491-
subsequent = true;
492-
493-
} else {
494-
subidentifier = (uint64_t)strtol(buffer, NULL, 10);
495-
}
496-
497-
/*
498-
* We will be reading the subidentifier 7 bits at a time. This is because the
499-
* OID components are encoded in a variable length format, where the high bit
500-
* of each byte indicates if there are more bytes to follow.
501-
*/
502-
while (bit_index > 7) {
503-
if (!started_subidentifier && ((uint8_t)(subidentifier >> (bit_index - 8)) == 0)) {
504-
bit_index -= 8;
505-
continue;
506-
}
507-
508-
if (!started_subidentifier) {
509-
byte = (uint8_t)(subidentifier >> (bit_index -= (bit_index % 7)));
510-
511-
if (byte == 0) {
512-
if (bit_index <= 7) {
513-
break;
514-
}
469+
oid = strtoull(start, &end, 10);
470+
if (!((oid == 0) || (oid == 1) || (oid == 2)) ||
471+
!end || (*end != '.')) {
472+
invalid_oid:
473+
fr_strerror_const("Invalid OID");
474+
return -1;
475+
}
515476

516-
byte = (uint8_t)(subidentifier >> (bit_index -= 7));
477+
first_component = oid;
517478

518-
if (byte == 0) {
519-
byte = (uint8_t)(subidentifier >> (bit_index -= 7));
520-
}
521-
}
479+
/*
480+
* Loop until we're done the string.
481+
*/
482+
while (*end) {
483+
int i;
522484

523-
} else {
524-
byte = (uint8_t)(subidentifier >> (bit_index -= 7));
525-
}
485+
/*
486+
* The previous round MUST have ended with '.'
487+
*/
488+
start = end + 1;
489+
if (!*start) goto invalid_oid; /* OID=1 or OID=1.2. is not allowed */
526490

527-
byte = byte | 0x80; /* Set the high bit to indicate more bytes to follow */
491+
/*
492+
* Parse the component.
493+
*/
494+
oid = strtoull(start, &end, 10);
495+
if (oid == ULLONG_MAX) goto invalid_oid;
496+
if (*end && (*end != '.')) goto invalid_oid;
528497

529-
FR_DBUFF_IN_RETURN(&our_dbuff, byte);
530-
started_subidentifier = true;
531-
}
498+
/*
499+
* The initial packed field has the first two compenents included, as (x * 40) + y.
500+
*/
501+
if (first) {
502+
if (oid > (((unsigned long long) 1) << 60)) goto invalid_oid; /* avoid overflow */
503+
first = false;
504+
oid += first_component * 40;
505+
}
532506

533-
/*
534-
* Tack on the last byte
535-
*/
536-
byte = (uint8_t)(subidentifier);
507+
/*
508+
* Encode the number as 7-bit chunks. Just brute-force over all bits, as doing that ends
509+
* up being fast enough.
510+
*
511+
* i.e. if we did anything else to count bits, it would end up with pretty much the same
512+
* code.
513+
*/
514+
for (i = 63; i >= 0; i -= 7) {
515+
uint8_t more, part;
537516

538-
byte = byte & 0x7f;
517+
part = (oid >> i) & 0x7f;
518+
if (!part) continue;
539519

540-
FR_DBUFF_IN_RETURN(&our_dbuff, byte);
541-
memset(buffer, 0, sizeof(buffer));
542-
buffer_len = 0;
520+
more = ((uint8_t) (i > 0)) << 7;
543521

544-
continue;
522+
FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) (more | part));
545523
}
546-
547-
buffer[buffer_len++] = oid_str[index];
548524
}
549525

550526
return fr_dbuff_set(dbuff, &our_dbuff);

0 commit comments

Comments
 (0)