diff --git a/ChangeLog b/ChangeLog index fbb2510e..cb6b9d4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ * Fixed parser: memory leak in free_struct code for SET OF/SEQUENCE OF. (Severity: high, Security impact: medium) + * Improved INTEGER type printing. 0.8.14: 2004-Jun-30 diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c index d20379fb..120b94fe 100644 --- a/skeletons/INTEGER.c +++ b/skeletons/INTEGER.c @@ -186,8 +186,8 @@ INTEGER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr, int INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + char scratch[32]; /* Enough for 64-bit integer */ const INTEGER_t *st = sptr; - char scratch[32]; uint8_t *buf = st->buf; uint8_t *buf_end = st->buf + st->size; signed long accum; @@ -202,9 +202,24 @@ INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, if(st->size == 0) return cb("0", 1, app_key); + /* + * Advance buf pointer until the start of the value's body. + * This will make us able to process large integers using simple case, + * when the actual value is small + * (0x0000000000abcdef would yield a fine 0x00abcdef) + */ + /* Skip the insignificant leading bytes */ + for(; buf < buf_end-1; buf++) { + switch(*buf) { + case 0x00: if((buf[1] & 0x80) == 0) continue; break; + case 0xff: if((buf[1] & 0x80) != 0) continue; break; + } + break; + } + /* Simple case: the integer size is small */ - if((size_t)st->size < sizeof(accum) || (st->buf[0] & 0x80)) { - accum = (st->buf[0] & 0x80) ? -1 : 0; + if((size_t)(buf_end - buf) <= sizeof(accum)) { + accum = (*buf & 0x80) ? -1 : 0; for(; buf < buf_end; buf++) accum = (accum << 8) | *buf; ret = snprintf(scratch, sizeof(scratch), "%ld", accum); @@ -213,9 +228,10 @@ INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, } /* Output in the long xx:yy:zz... format */ + /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ for(p = scratch; buf < buf_end; buf++) { static char h2c[16] = "0123456789ABCDEF"; - if((p - scratch) >= (ssize_t)(sizeof(scratch) / 2)) { + if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { /* Flush buffer */ if(cb(scratch, p - scratch, app_key)) return -1; @@ -225,6 +241,8 @@ INTEGER_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, *p++ = h2c[*buf & 0x0F]; *p++ = ':'; } + if(p != scratch) + p--; /* Remove the last ':' */ return cb(scratch, p - scratch, app_key); } diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c index 8203695c..8f13a591 100644 --- a/skeletons/NativeInteger.c +++ b/skeletons/NativeInteger.c @@ -166,7 +166,7 @@ int NativeInteger_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { const int *Int = sptr; - char scratch[32]; + char scratch[32]; /* Enough for 64-bit int */ int ret; (void)td; /* Unused argument */ diff --git a/skeletons/tests/check-INTEGER.c b/skeletons/tests/check-INTEGER.c index 4053075e..5aa400d5 100644 --- a/skeletons/tests/check-INTEGER.c +++ b/skeletons/tests/check-INTEGER.c @@ -5,9 +5,22 @@ #include "../der_encoder.c" #include "../constraints.c" +static char *shared_scratch_start; + +static int _print2buf(const void *buf, size_t size, void *key) { + (void)key; + memcpy(shared_scratch_start, buf, size); + shared_scratch_start += size; + *shared_scratch_start = '\0'; /* 0-termination */ + return 0; +} + static void check(uint8_t *buf, int size, long check_long, int check_ret) { + char scratch[128]; + char verify[32]; INTEGER_t val; + uint8_t *buf_end = buf + size; int ret; long rlong = 123; @@ -17,13 +30,35 @@ check(uint8_t *buf, int size, long check_long, int check_ret) { val.buf = buf; val.size = size; + printf("Testing: ["); + for(; buf < buf_end; buf++) { + if(buf != val.buf) printf(":"); + printf("%02x", *buf); + } + printf("]: "); ret = asn1_INTEGER2long(&val, &rlong); - printf("Testing (%ld, %d) vs (%ld, %d)\n", + printf(" (%ld, %d) vs (%ld, %d)\n", rlong, ret, check_long, check_ret); assert(ret == check_ret); - if(ret == -1) return; assert(rlong == check_long); + + shared_scratch_start = scratch; + ret = INTEGER_print(&asn1_DEF_INTEGER, &val, 0, _print2buf, scratch); + assert(shared_scratch_start < scratch + sizeof(scratch)); + assert(ret == 0); + ret = snprintf(verify, sizeof(verify), "%ld", check_long); + assert(ret < sizeof(verify)); + ret = strcmp(scratch, verify); + printf(" [%s] vs [%s]: %d%s\n", + scratch, verify, ret, + (check_ret == -1)?" (expected to fail)":"" + ); + if(check_ret == -1) { + assert(strcmp(scratch, verify)); + } else { + assert(strcmp(scratch, verify) == 0); + } } int