summaryrefslogtreecommitdiff
path: root/src/ber-decoder.c
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-12-23 10:55:49 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-12-23 10:55:49 +0900
commit9fd74865e44c3af62343386d35d326df9e49161d (patch)
tree77f3a57dcb1482a5c6e324c0ae62ab20107e45af /src/ber-decoder.c
parent8f617f621304d77e839de3ff1ef2c09347b612d9 (diff)
downloadlibksba-9fd74865e44c3af62343386d35d326df9e49161d.tar.gz
libksba-9fd74865e44c3af62343386d35d326df9e49161d.tar.bz2
libksba-9fd74865e44c3af62343386d35d326df9e49161d.zip
Imported Upstream version 1.3.3upstream/1.3.3
Diffstat (limited to 'src/ber-decoder.c')
-rw-r--r--src/ber-decoder.c101
1 files changed, 72 insertions, 29 deletions
diff --git a/src/ber-decoder.c b/src/ber-decoder.c
index 873f810..9e70d92 100644
--- a/src/ber-decoder.c
+++ b/src/ber-decoder.c
@@ -1,5 +1,5 @@
/* ber-decoder.c - Basic Encoding Rules Decoder
- * Copyright (C) 2001, 2004, 2006, 2012 g10 Code GmbH
+ * Copyright (C) 2001, 2004, 2006, 2012, 2015 g10 Code GmbH
*
* This file is part of KSBA.
*
@@ -100,7 +100,7 @@ struct ber_decoder_s
struct
{
int primitive; /* current value is a primitive one */
- int length; /* length of the primitive one */
+ size_t length; /* length of the primitive one */
int nhdr; /* length of the header */
int tag;
int is_endtag;
@@ -109,6 +109,23 @@ struct ber_decoder_s
};
+
+/* Evaluate with overflow check: A1 + A2 > B */
+static inline int
+sum_a1_a2_gt_b (size_t a1, size_t a2, size_t b)
+{
+ size_t sum = a1 + a2;
+ return (sum < a1 || sum > b);
+}
+
+/* Evaluate with overflow check: A1 + A2 >= B */
+static inline int
+sum_a1_a2_ge_b (size_t a1, size_t a2, size_t b)
+{
+ size_t sum = a1 + a2;
+ return (sum < a1 || sum >= b);
+}
+
static DECODER_STATE
@@ -158,26 +175,28 @@ dump_decoder_state (DECODER_STATE ds)
}
/* Push ITEM onto the stack */
-static void
+static gpg_error_t
push_decoder_state (DECODER_STATE ds)
{
if (ds->idx >= ds->stacksize)
{
- fprintf (stderr, "ERROR: decoder stack overflow!\n");
- abort ();
+ fprintf (stderr, "ksba: ber-decoder: stack overflow!\n");
+ return gpg_error (GPG_ERR_LIMIT_REACHED);
}
ds->stack[ds->idx++] = ds->cur;
+ return 0;
}
-static void
+static gpg_error_t
pop_decoder_state (DECODER_STATE ds)
{
if (!ds->idx)
{
- fprintf (stderr, "ERROR: decoder stack underflow!\n");
- abort ();
+ fprintf (stderr, "ksba: ber-decoder: stack underflow!\n");
+ return gpg_error (GPG_ERR_INTERNAL);
}
ds->cur = ds->stack[--ds->idx];
+ return 0;
}
@@ -185,7 +204,7 @@ pop_decoder_state (DECODER_STATE ds)
static int
set_error (BerDecoder d, AsnNode node, const char *text)
{
- fprintf (stderr,"ber-decoder: node `%s': %s\n",
+ fprintf (stderr,"ksba: ber-decoder: node `%s': %s\n",
node? node->name:"?", text);
d->last_errdesc = text;
return gpg_error (GPG_ERR_BAD_BER);
@@ -839,14 +858,16 @@ decoder_next (BerDecoder d)
{
/* We need some extra bytes to store the stuff we read ahead
at the end of the module which is later pushed back. */
- d->image.length = ti.length + 100;
d->image.used = 0;
+ d->image.length = ti.length + 100;
+ if (d->image.length < ti.length)
+ return gpg_error (GPG_ERR_BAD_BER);
d->image.buf = xtrymalloc (d->image.length);
if (!d->image.buf)
return gpg_error (GPG_ERR_ENOMEM);
}
- if (ti.nhdr + d->image.used >= d->image.length)
+ if (sum_a1_a2_ge_b (ti.nhdr, d->image.used, d->image.length))
return set_error (d, NULL, "image buffer too short to store the tag");
memcpy (d->image.buf + d->image.used, ti.buf, ti.nhdr);
@@ -936,9 +957,9 @@ decoder_next (BerDecoder d)
&& (ds->cur.nread
> ds->stack[ds->idx-1].length))
{
- fprintf (stderr, " ERROR: object length field "
+ fprintf (stderr, "ksba: ERROR: object length field "
"%d octects too large\n",
- ds->cur.nread > ds->cur.length);
+ ds->cur.nread - ds->cur.length);
ds->cur.nread = ds->cur.length;
}
if ( ds->idx
@@ -948,7 +969,9 @@ decoder_next (BerDecoder d)
>= ds->stack[ds->idx-1].length))))
{
int n = ds->cur.nread;
- pop_decoder_state (ds);
+ err = pop_decoder_state (ds);
+ if (err)
+ return err;
ds->cur.nread += n;
ds->cur.went_up++;
}
@@ -964,7 +987,9 @@ decoder_next (BerDecoder d)
/* prepare for the next level */
ds->cur.length = ti.length;
ds->cur.ndef_length = ti.ndef;
- push_decoder_state (ds);
+ err = push_decoder_state (ds);
+ if (err)
+ return err;
ds->cur.length = 0;
ds->cur.ndef_length = 0;
ds->cur.nread = 0;
@@ -1041,7 +1066,7 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp)
int depth = 0;
AsnNode node;
unsigned char *buf = NULL;
- size_t buflen = 0;;
+ size_t buflen = 0;
if (!d)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -1063,9 +1088,9 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp)
if (node)
depth = distance (d->root, node);
- fprintf (fp, "%4lu %4u:%*s",
+ fprintf (fp, "%4lu %4lu:%*s",
ksba_reader_tell (d->reader) - d->val.nhdr,
- d->val.length,
+ (unsigned long)d->val.length,
depth*2, "");
if (node)
_ksba_asn_node_dump (node, fp);
@@ -1074,16 +1099,22 @@ _ksba_ber_decoder_dump (BerDecoder d, FILE *fp)
if (node && d->val.primitive)
{
- int i, n, c;
+ size_t n;
+ int i, c;
char *p;
if (!buf || buflen < d->val.length)
{
xfree (buf);
buflen = d->val.length + 100;
- buf = xtrymalloc (buflen);
- if (!buf)
- err = gpg_error (GPG_ERR_ENOMEM);
+ if (buflen < d->val.length)
+ err = gpg_error (GPG_ERR_BAD_BER); /* Overflow */
+ else
+ {
+ buf = xtrymalloc (buflen);
+ if (!buf)
+ err = gpg_error_from_syserror ();
+ }
}
for (n=0; !err && n < d->val.length; n++)
@@ -1171,8 +1202,6 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name,
while (!(err = decoder_next (d)))
{
- int n, c;
-
node = d->val.node;
/* Fixme: USE_IMAGE is only not used with the ber-dump utility
and thus of no big use. We should remove the other code
@@ -1188,7 +1217,7 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name,
if (node->type == TYPE_ANY)
node->actual_type = d->val.tag;
}
- if (d->image.used + d->val.length > d->image.length)
+ if (sum_a1_a2_gt_b (d->image.used, d->val.length, d->image.length))
err = set_error(d, NULL, "TLV length too large");
else if (d->val.primitive)
{
@@ -1196,18 +1225,32 @@ _ksba_ber_decoder_decode (BerDecoder d, const char *start_name,
d->image.buf + d->image.used, d->val.length))
err = eof_or_error (d, 1);
else
- d->image.used += d->val.length;
+ {
+ size_t sum = d->image.used + d->val.length;
+ if (sum < d->image.used)
+ err = gpg_error (GPG_ERR_BAD_BER);
+ else
+ d->image.used = sum;
+ }
}
}
else if (node && d->val.primitive)
{
+ size_t n;
+ int c;
+
if (!buf || buflen < d->val.length)
{
xfree (buf);
buflen = d->val.length + 100;
- buf = xtrymalloc (buflen);
- if (!buf)
- err = gpg_error (GPG_ERR_ENOMEM);
+ if (buflen < d->val.length)
+ err = gpg_error (GPG_ERR_BAD_BER);
+ else
+ {
+ buf = xtrymalloc (buflen);
+ if (!buf)
+ err = gpg_error_from_syserror ();
+ }
}
for (n=0; !err && n < d->val.length; n++)