#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: der.c,v 1.9 2016/10/24 15:19:08 christos Exp $")
+FILE_RCSID("@(#)$File: der.c,v 1.10 2016/10/24 18:02:17 christos Exp $")
#endif
#endif
return tag;
}
+/*
+ * Read the length of a DER tag from the input.
+ *
+ * `c` is the input, `p` is an output parameter that specifies how much of the
+ * input we consumed, and `l` is the maximum input length.
+ *
+ * Returns the length, or DER_BAD if the end of the input is reached or the
+ * length exceeds the remaining input.
+ */
static uint32_t
getlength(const uint8_t *c, size_t *p, size_t l)
{
uint8_t digits, i;
size_t len;
+ int is_onebyte_result;
if (*p >= l)
return DER_BAD;
- digits = c[(*p)++];
+ /*
+ * Digits can either be 0b0 followed by the result, or 0b1
+ * followed by the number of digits of the result. In either case,
+ * we verify that we can read so many bytes from the input.
+ */
+ is_onebyte_result = (c[*p] & 0x80) == 0;
+ digits = c[(*p)++] & 0x7f;
+ if (*p + digits >= l)
+ return DER_BAD;
- if ((digits & 0x80) == 0)
+ if (is_onebyte_result)
return digits;
- digits &= 0x7f;
+ /*
+ * Decode len. We've already verified that we're allowed to read
+ * `digits` bytes.
+ */
len = 0;
-
- if (*p + digits >= l)
- return DER_BAD;
-
for (i = 0; i < digits; i++)
len = (len << 8) | c[(*p)++];
+
if (*p + len >= l)
return DER_BAD;
- return len;
+ return len;
}
static const char *