@@ -453,12 +453,11 @@ static ssize_t fr_der_encode_null(UNUSED fr_dbuff_t *dbuff, fr_dcursor_t *cursor
453453static 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