Fix XER decoder of INTEGER, Issue #344.
In some cases an INTEGER overflow during parsing is not detected
and incorrect value is returned to the decoder instead of an error.
Reported by Nika Pona <npona@digamma.ai>.
(Severity: low; Seuciry impact: medium).
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 73da665..2b43cdf 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -1,5 +1,5 @@
-/*-
- * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.
+/*
+ * Copyright (c) 2003-2019 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
@@ -1032,64 +1032,71 @@
*/
enum asn_strtox_result_e
asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) {
- int sign = 1;
- intmax_t value;
+ int sign = 1;
+ intmax_t value;
-#define ASN1_INTMAX_MAX ((~(uintmax_t)0) >> 1)
- const intmax_t upper_boundary = ASN1_INTMAX_MAX / 10;
- intmax_t last_digit_max = ASN1_INTMAX_MAX % 10;
-#undef ASN1_INTMAX_MAX
+ const intmax_t asn1_intmax_max = ((~(uintmax_t)0) >> 1);
+ const intmax_t upper_boundary = asn1_intmax_max / 10;
+ intmax_t last_digit_max = asn1_intmax_max % 10;
- if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
+ if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
- switch(*str) {
- case '-':
- last_digit_max++;
- sign = -1;
- /* FALL THROUGH */
- case '+':
- str++;
- if(str >= *end) {
- *end = str;
- return ASN_STRTOX_EXPECT_MORE;
- }
- }
+ switch(*str) {
+ case '-':
+ last_digit_max++;
+ sign = -1;
+ /* FALL THROUGH */
+ case '+':
+ str++;
+ if(str >= *end) {
+ *end = str;
+ return ASN_STRTOX_EXPECT_MORE;
+ }
+ }
- for(value = 0; str < (*end); str++) {
- switch(*str) {
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
- case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
- int d = *str - '0';
- if(value < upper_boundary) {
- value = value * 10 + d;
- } else if(value == upper_boundary) {
- if(d <= last_digit_max) {
- if(sign > 0) {
- value = value * 10 + d;
- } else {
- sign = 1;
- value = -value * 10 - d;
- }
- } else {
- *end = str;
- return ASN_STRTOX_ERROR_RANGE;
- }
- } else {
- *end = str;
- return ASN_STRTOX_ERROR_RANGE;
- }
- }
- continue;
- default:
- *end = str;
- *intp = sign * value;
- return ASN_STRTOX_EXTRA_DATA;
- }
- }
+ for(value = 0; str < (*end); str++) {
+ if(*str >= 0x30 && *str <= 0x39) {
+ int d = *str - '0';
+ if(value < upper_boundary) {
+ value = value * 10 + d;
+ } else if(value == upper_boundary) {
+ if(d <= last_digit_max) {
+ if(sign > 0) {
+ value = value * 10 + d;
+ } else {
+ sign = 1;
+ value = -value * 10 - d;
+ }
+ str += 1;
+ if(str < *end) {
+ // If digits continue, we're guaranteed out of range.
+ *end = str;
+ if(*str >= 0x30 && *str <= 0x39) {
+ return ASN_STRTOX_ERROR_RANGE;
+ } else {
+ *intp = sign * value;
+ return ASN_STRTOX_EXTRA_DATA;
+ }
+ }
+ break;
+ } else {
+ *end = str;
+ return ASN_STRTOX_ERROR_RANGE;
+ }
+ } else {
+ *end = str;
+ return ASN_STRTOX_ERROR_RANGE;
+ }
+ } else {
+ *end = str;
+ *intp = sign * value;
+ return ASN_STRTOX_EXTRA_DATA;
+ }
+ }
- *end = str;
- *intp = sign * value;
- return ASN_STRTOX_OK;
+ *end = str;
+ *intp = sign * value;
+ return ASN_STRTOX_OK;
}
/*
@@ -1100,56 +1107,63 @@
*/
enum asn_strtox_result_e
asn_strtoumax_lim(const char *str, const char **end, uintmax_t *uintp) {
- uintmax_t value;
+ uintmax_t value;
-#define ASN1_UINTMAX_MAX ((~(uintmax_t)0))
- const uintmax_t upper_boundary = ASN1_UINTMAX_MAX / 10;
- uintmax_t last_digit_max = ASN1_UINTMAX_MAX % 10;
-#undef ASN1_UINTMAX_MAX
+ const uintmax_t asn1_uintmax_max = ((~(uintmax_t)0));
+ const uintmax_t upper_boundary = asn1_uintmax_max / 10;
+ uintmax_t last_digit_max = asn1_uintmax_max % 10;
if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
- switch(*str) {
- case '-':
+ switch(*str) {
+ case '-':
return ASN_STRTOX_ERROR_INVAL;
- case '+':
- str++;
- if(str >= *end) {
- *end = str;
- return ASN_STRTOX_EXPECT_MORE;
- }
- }
+ case '+':
+ str++;
+ if(str >= *end) {
+ *end = str;
+ return ASN_STRTOX_EXPECT_MORE;
+ }
+ }
- for(value = 0; str < (*end); str++) {
- switch(*str) {
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
- case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
- unsigned int d = *str - '0';
- if(value < upper_boundary) {
- value = value * 10 + d;
- } else if(value == upper_boundary) {
- if(d <= last_digit_max) {
+ for(value = 0; str < (*end); str++) {
+ if(*str >= 0x30 && *str <= 0x39) {
+ unsigned int d = *str - '0';
+ if(value < upper_boundary) {
+ value = value * 10 + d;
+ } else if(value == upper_boundary) {
+ if(d <= last_digit_max) {
value = value * 10 + d;
+ str += 1;
+ if(str < *end) {
+ // If digits continue, we're guaranteed out of range.
+ *end = str;
+ if(*str >= 0x30 && *str <= 0x39) {
+ return ASN_STRTOX_ERROR_RANGE;
+ } else {
+ *uintp = value;
+ return ASN_STRTOX_EXTRA_DATA;
+ }
+ }
+ break;
} else {
- *end = str;
- return ASN_STRTOX_ERROR_RANGE;
- }
- } else {
- *end = str;
- return ASN_STRTOX_ERROR_RANGE;
- }
- }
- continue;
- default:
- *end = str;
- *uintp = value;
- return ASN_STRTOX_EXTRA_DATA;
- }
- }
+ *end = str;
+ return ASN_STRTOX_ERROR_RANGE;
+ }
+ } else {
+ *end = str;
+ return ASN_STRTOX_ERROR_RANGE;
+ }
+ } else {
+ *end = str;
+ *uintp = value;
+ return ASN_STRTOX_EXTRA_DATA;
+ }
+ }
- *end = str;
- *uintp = value;
- return ASN_STRTOX_OK;
+ *end = str;
+ *uintp = value;
+ return ASN_STRTOX_OK;
}
enum asn_strtox_result_e