return 0;
}
-static ssize_t fr_der_encode_oid_from_str(fr_dbuff_t *dbuff, const char *oid_str)
+static ssize_t fr_der_encode_oid_from_value(fr_dbuff_t *dbuff, uint64_t value, uint64_t *component, int *count)
{
- fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
- bool first = true;
- uint8_t first_component;
- unsigned long long oid;
- char const *start = oid_str;
- char *end = NULL;
+ fr_dbuff_t our_dbuff;
+ int i;
+ uint64_t oid;
/*
* The first subidentifier is the encoding of the first two object identifier components, encoded as:
* where X is the first number and Y is the second number.
* The first number is 0, 1, or 2.
*/
+ if (*count == 0) {
+ if (!((value == 0) || (value == 1) || (value == 2))) {
+ fr_strerror_printf("Invalid value %" PRIu64 " for initial component", value);
+ return -1;
+ }
- oid = strtoull(start, &end, 10);
- if (!((oid == 0) || (oid == 1) || (oid == 2)) ||
- !end || (*end != '.')) {
- invalid_oid:
- fr_strerror_const("Invalid OID");
- return -1;
+ *component = value;
+ (*count)++;
+ return 0;
}
- first_component = oid;
+ if (*count == 1) {
+ if ((*component < 2) && (value > 40)) {
+ fr_strerror_printf("Invalid value %" PRIu64 " for second component", value);
+ return -1;
+ }
+
+ oid = *component * 40 + value;
+ } else {
+ oid = value;
+ }
+
+ our_dbuff = FR_DBUFF(dbuff);
/*
- * Loop until we're done the string.
+ * Encode the number as 7-bit chunks. Just brute-force over all bits, as doing that ends
+ * up being fast enough.
+ *
+ * i.e. if we did anything else to count bits, it would end up with pretty much the same
+ * code.
*/
- while (*end) {
- int i;
+ for (i = 63; i >= 0; i -= 7) {
+ uint8_t more, part;
- /*
- * The previous round MUST have ended with '.'
- */
- start = end + 1;
- if (!*start) goto invalid_oid; /* OID=1 or OID=1.2. is not allowed */
+ part = (oid >> i) & 0x7f;
+ if (!part) continue;
- /*
- * Parse the component.
- */
- oid = strtoull(start, &end, 10);
- if (oid == ULLONG_MAX) goto invalid_oid;
- if (*end && (*end != '.')) goto invalid_oid;
+ more = ((uint8_t) (i > 0)) << 7;
- /*
- * The initial packed field has the first two compenents included, as (x * 40) + y.
- */
- if (first) {
- if (first_component < 2) {
- if (oid >= 40) goto invalid_oid;
+ FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) (more | part));
+ }
- } else {
- if (oid > (((unsigned long long) 1) << 60)) goto invalid_oid; /* avoid overflow */
- }
+ (*count)++;
- first = false;
- oid += first_component * 40;
- }
+ return fr_dbuff_set(dbuff, &our_dbuff);
+}
+
+static ssize_t fr_der_encode_oid_from_str(fr_dbuff_t *dbuff, const char *oid_str)
+{
+ fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
+ uint64_t component;
+ int count = 0;
+ unsigned long long oid;
+ char const *start = oid_str;
+ char *end = NULL;
+
+ /*
+ * Loop until we're done the string.
+ */
+ while (*start) {
+ ssize_t slen;
/*
- * Encode the number as 7-bit chunks. Just brute-force over all bits, as doing that ends
- * up being fast enough.
- *
- * i.e. if we did anything else to count bits, it would end up with pretty much the same
- * code.
+ * Parse the component.
*/
- for (i = 63; i >= 0; i -= 7) {
- uint8_t more, part;
-
- part = (oid >> i) & 0x7f;
- if (!part) continue;
+ oid = strtoull(start, &end, 10);
+ if ((oid == ULLONG_MAX) || (*end && (*end != '.'))) {
+ fr_strerror_const("Invalid OID");
+ return -1;
+ }
- more = ((uint8_t) (i > 0)) << 7;
+ slen = fr_der_encode_oid_from_value(&our_dbuff, oid, &component, &count);
+ if (slen < 0) return -1;
- FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) (more | part));
- }
+ start = end + 1;
}
return fr_dbuff_set(dbuff, &our_dbuff);
static ssize_t fr_der_encode_oid_and_value(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx)
{
fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
- fr_sbuff_t oid_sbuff;
fr_dbuff_marker_t length_start;
fr_dcursor_t child_cursor, parent_cursor = *cursor;
fr_pair_t const *vp, *child;
- char oid_buff[1024] = { 0 };
ssize_t slen = 0;
+ uint64_t component;
+ int count;
vp = fr_dcursor_current(&parent_cursor);
PAIR_VERIFY(vp);
* Note: The value may be a constructed or primitive type
*/
- oid_sbuff = FR_SBUFF_OUT(oid_buff, sizeof(oid_buff));
- oid_buff[0] = '\0';
+ slen = fr_der_encode_tag(&our_dbuff, FR_DER_TAG_OID, FR_DER_CLASS_UNIVERSAL, FR_DER_TAG_PRIMITIVE);
+ if (slen < 0) return slen;
+
+ fr_dbuff_marker(&length_start, &our_dbuff);
+ FR_DBUFF_ADVANCE_RETURN(&our_dbuff, 1);
/*
* Walk through the children until we find either an attribute marked as an oid leaf, or one with
* pair.
*/
fr_pair_dcursor_child_iter_init(&child_cursor, &vp->children, &parent_cursor);
+ count = 0;
+
while ((child = fr_dcursor_current(&child_cursor)) != NULL) {
PAIR_VERIFY(child);
+ /*
+ * We stop encoding at a leaf.
+ */
if (!fr_type_is_structural(child->vp_type) && !fr_der_flag_is_oid_leaf(child->da)) {
FR_PROTO_TRACE("Found non-structural child %s", child->da->name);
if (child->da->flags.is_raw) {
- /*
- * This was an unknown oid
- */
- if (unlikely(fr_sbuff_in_sprintf(&oid_sbuff, ".%" PRIu32, child->da->attr) <= 0)) {
- fr_strerror_const("Failed to copy OID to buffer");
- return slen;
- }
+ slen = fr_der_encode_oid_from_value(&our_dbuff, child->da->attr, &component, &count);
+ if (unlikely(slen < 0)) return -1;
break;
}
break;
}
- if (oid_buff[0] == '\0') {
- if (unlikely(fr_sbuff_in_sprintf(&oid_sbuff, "%" PRIu32, child->da->attr) <= 0)) {
- fr_strerror_const("Failed to copy OID to buffer");
- return -1;
- }
-
- goto next;
- }
-
- if (unlikely(fr_sbuff_in_sprintf(&oid_sbuff, ".%" PRIu32, child->da->attr) <= 0)) {
- fr_strerror_const("Failed to copy OID to buffer");
- return -1;
- }
+ slen = fr_der_encode_oid_from_value(&our_dbuff, child->da->attr, &component, &count);
+ if (unlikely(slen < 0)) return -1;
/*
* Unless this was the last child (marked as an oid leaf), there should only be one child
*/
if (fr_pair_list_num_elements(&child->children) > 1) break;
- next:
- FR_PROTO_TRACE("OID: %s", oid_buff);
if (fr_der_flag_is_oid_leaf(child->da)) break;
fr_pair_dcursor_child_iter_init(&child_cursor, &child->children, &child_cursor);
}
- fr_sbuff_terminate(&oid_sbuff);
- FR_PROTO_TRACE("OID: %s", oid_buff);
-
- slen = fr_der_encode_tag(&our_dbuff, FR_DER_TAG_OID, FR_DER_CLASS_UNIVERSAL, FR_DER_TAG_PRIMITIVE);
- if (slen < 0) return slen;
-
- fr_dbuff_marker(&length_start, &our_dbuff);
- FR_DBUFF_ADVANCE_RETURN(&our_dbuff, 1);
-
- /*
- * Encode the OID portion of the pair
- */
- slen = fr_der_encode_oid_from_str(&our_dbuff, oid_buff);
- if (slen < 0) {
- fr_dbuff_marker_release(&length_start);
- return slen;
- }
-
/*
* Encode the length of the OID
*/