Commit 5c915993 authored by Lev Walkin's avatar Lev Walkin

better handling of encoded subTLVs

parent ed46543c
...@@ -93,10 +93,11 @@ asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = { ...@@ -93,10 +93,11 @@ asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = {
*/ */
struct _stack_el { struct _stack_el {
ber_tlv_len_t left; /* What's left to read (or -1) */ ber_tlv_len_t left; /* What's left to read (or -1) */
ber_tlv_len_t frame; /* What was planned to read (or -1) */ ber_tlv_len_t got; /* What was actually processed */
int cont_level; /* Depth of subcontainment */ int cont_level; /* Depth of subcontainment */
int want_nulls; /* Want null "end of content" octets? */ int want_nulls; /* Want null "end of content" octets? */
int bits_chopped; /* Flag in BIT STRING mode */ int bits_chopped; /* Flag in BIT STRING mode */
ber_tlv_tag_t tag; /* For debugging purposes */
struct _stack_el *prev; struct _stack_el *prev;
struct _stack_el *next; struct _stack_el *next;
}; };
...@@ -115,7 +116,8 @@ OS__add_stack_el(struct _stack *st) { ...@@ -115,7 +116,8 @@ OS__add_stack_el(struct _stack *st) {
if(st->cur_ptr && st->cur_ptr->next) { if(st->cur_ptr && st->cur_ptr->next) {
nel = st->cur_ptr->next; nel = st->cur_ptr->next;
nel->bits_chopped = 0; nel->bits_chopped = 0;
/* Retain nel->cont_level, it's correct. */ nel->got = 0;
/* Retain the nel->cont_level, it's correct. */
} else { } else {
(void *)nel = CALLOC(1, sizeof(struct _stack_el)); (void *)nel = CALLOC(1, sizeof(struct _stack_el));
if(nel == NULL) if(nel == NULL)
...@@ -156,7 +158,7 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -156,7 +158,7 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
ber_dec_ctx_t *ctx; ber_dec_ctx_t *ctx;
ssize_t consumed_myself = 0; ssize_t consumed_myself = 0;
struct _stack *stck; /* A stack structure */ struct _stack *stck; /* A stack structure */
struct _stack_el *sel; /* Stack element */ struct _stack_el *sel = 0; /* Stack element */
int tlv_constr; int tlv_constr;
enum type_type_e { enum type_type_e {
_TT_GENERIC = 0, /* Just a random OCTET STRING */ _TT_GENERIC = 0, /* Just a random OCTET STRING */
...@@ -231,16 +233,40 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -231,16 +233,40 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
ber_tlv_tag_t tlv_tag; ber_tlv_tag_t tlv_tag;
ber_tlv_len_t tlv_len; ber_tlv_len_t tlv_len;
ber_tlv_tag_t expected_tag; ber_tlv_tag_t expected_tag;
ssize_t tl, ll; ssize_t tl, ll, tlvl;
/* This one works even if (sel->left == -1) */ /* This one works even if (sel->left == -1) */
ssize_t Left = ((!sel||(size_t)sel->left >= size) ssize_t Left = ((!sel||(size_t)sel->left >= size)
?size:(size_t)sel->left); ?(ssize_t)size:sel->left);
ASN_DEBUG("fetch tag(size=%d,L=%d), %sstack, left=%d, want0=%d", ASN_DEBUG("%p, s->l=%d, s->wn=%d, s->g=%d\n", sel,
(int)size, Left, sel?"":"!", sel?sel->left:0,
sel?sel->left:0, sel?sel->want_nulls:0); sel?sel->want_nulls:0,
sel?sel->got:0
);
if(sel && sel->left <= 0 && sel->want_nulls == 0) {
if(sel->prev) {
struct _stack_el *prev = sel->prev;
if(prev->left != -1) {
if(prev->left < sel->got)
RETURN(RC_FAIL);
prev->left -= sel->got;
}
prev->got += sel->got;
sel = stck->cur_ptr = prev;
if(!sel) break;
tlv_constr = 1;
continue;
} else {
sel = stck->cur_ptr = 0;
break; /* Nothing to wait */
}
}
tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
ASN_DEBUG("fetch tag(size=%d,L=%d), %sstack, left=%d, wn=%d, tl=%d",
(int)size, Left, sel?"":"!",
sel?sel->left:0, sel?sel->want_nulls:0, tl);
switch(tl) { switch(tl) {
case -1: RETURN(RC_FAIL); case -1: RETURN(RC_FAIL);
case 0: RETURN(RC_WMORE); case 0: RETURN(RC_WMORE);
...@@ -250,11 +276,9 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -250,11 +276,9 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
ll = ber_fetch_length(tlv_constr, ll = ber_fetch_length(tlv_constr,
(char *)buf_ptr + tl, Left - tl, &tlv_len); (char *)buf_ptr + tl, Left - tl, &tlv_len);
ASN_DEBUG("Got tag=%s, tc=%d, size=%d, tl=%d, len=%d, ll=%d, {%d, %d}", ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%d, len=%d, ll=%d",
ber_tlv_tag_string(tlv_tag), tlv_constr, ber_tlv_tag_string(tlv_tag), tlv_constr,
(int)Left, tl, tlv_len, ll, (long)Left, tl, tlv_len, ll);
((uint8_t *)buf_ptr)[0],
((uint8_t *)buf_ptr)[1]);
switch(ll) { switch(ll) {
case -1: RETURN(RC_FAIL); case -1: RETURN(RC_FAIL);
case 0: RETURN(RC_WMORE); case 0: RETURN(RC_WMORE);
...@@ -264,26 +288,21 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -264,26 +288,21 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
&& ((uint8_t *)buf_ptr)[0] == 0 && ((uint8_t *)buf_ptr)[0] == 0
&& ((uint8_t *)buf_ptr)[1] == 0) && ((uint8_t *)buf_ptr)[1] == 0)
{ {
ADVANCE(2);
if(type_type == _TT_ANY) APPEND("\0\0", 2);
ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
if(type_type == _TT_ANY) APPEND("\0\0", 2);
ADVANCE(2);
sel->got += 2;
if(sel->left != -1) {
sel->left -= 2; /* assert(sel->left >= 2) */
}
sel->want_nulls--; sel->want_nulls--;
if(sel->want_nulls == 0) { if(sel->want_nulls == 0) {
/* Move to the next expectation */ /* Move to the next expectation */
sel = stck->cur_ptr = sel->prev; sel->left = 0;
if(sel == NULL)
break;
}
if(sel->want_nulls) {
/*
* Simulate while(TRUE) for this loop.
* This is necessary to fetch the next
* expectation after current "end of content",
* for which tlv_constr is 0.
*/
tlv_constr = 1; tlv_constr = 1;
} }
...@@ -330,34 +349,35 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -330,34 +349,35 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
RETURN(RC_FAIL); RETURN(RC_FAIL);
} }
/*
* Consult with the old expectation.
* Check that it knows what we are doing here, and how much.
*/
if(sel && sel->left != -1) {
if(sel->left < (tl + ll))
RETURN(RC_FAIL);
sel->left -= (tl + ll);
if(sel->left < tlv_len)
RETURN(RC_FAIL);
}
/* /*
* Append a new expectation. * Append a new expectation.
*/ */
sel = OS__add_stack_el(stck); sel = OS__add_stack_el(stck);
if(sel) { if(!sel) RETURN(RC_FAIL);
tlvl = tl + ll; /* Combined length of T and L encoding */
sel->tag = tlv_tag;
sel->want_nulls = (tlv_len==-1); sel->want_nulls = (tlv_len==-1);
sel->frame = sel->left = tlv_len; if(sel->prev && sel->prev->left != -1) {
ASN_DEBUG("+EXPECT2 frame=%d wn=%d, clvl=%d", /* Check that the parent frame is big enough */
sel->frame, sel->want_nulls, sel->cont_level); if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len))
} else {
RETURN(RC_FAIL); RETURN(RC_FAIL);
if(tlv_len == -1)
sel->left = sel->prev->left - tlvl;
else
sel->left = tlv_len;
} else {
sel->left = tlv_len;
} }
if(type_type == _TT_ANY) APPEND(buf_ptr, tlvl);
sel->got += tlvl;
ADVANCE(tlvl);
ASN_DEBUG("+EXPECT2 got=%d left=%d, wn=%d, clvl=%d",
sel->got, sel->left, sel->want_nulls, sel->cont_level);
if(type_type == _TT_ANY) APPEND(buf_ptr, tl + ll);
ADVANCE(tl+ll);
} while(tlv_constr); } while(tlv_constr);
if(sel == NULL) { if(sel == NULL) {
/* Finished operation, "phase out" */ /* Finished operation, "phase out" */
...@@ -371,8 +391,9 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -371,8 +391,9 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
case 2: case 2:
(void *)stck = ctx->ptr; (void *)stck = ctx->ptr;
sel = stck->cur_ptr; sel = stck->cur_ptr;
ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld", ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d",
(long)sel->left, (long)size); (long)sel->left, (long)size, (long)sel->got,
sel->want_nulls);
{ {
ber_tlv_len_t len; ber_tlv_len_t len;
...@@ -397,34 +418,18 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -397,34 +418,18 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
} }
ADVANCE(len); ADVANCE(len);
sel->left -= len; sel->left -= len;
sel->got += len;
} }
if(sel->left) if(sel->left) {
ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n",
(long)sel->left, (long)size, sel->want_nulls);
RETURN(RC_WMORE); RETURN(RC_WMORE);
while(sel->left == 0) {
ASN_DEBUG("sel %p, l=%d, f=%d, %p->l=%d p->f=%d\n",
sel, sel->left, sel->frame,
sel->prev,
sel->prev?sel->prev->left:0,
sel->prev?sel->prev->frame:0
);
if(sel->prev) {
if(sel->prev->left != -1) {
if(sel->prev->left < sel->frame)
RETURN(RC_FAIL);
sel->prev->left -= sel->frame;
} }
sel = stck->cur_ptr = sel->prev;
if(sel->left) {
PREV_PHASE(ctx); PREV_PHASE(ctx);
goto phase1; goto phase1;
} }
} else {
break;
}
}
}
break; break;
case 3: case 3:
phase3: phase3:
...@@ -446,6 +451,15 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -446,6 +451,15 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
break; break;
} }
if(sel) {
ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld",
sel->prev, sel->want_nulls,
(long)sel->left, (long)sel->got, (long)size);
if(sel->prev || sel->want_nulls > 1 || sel->left > 0) {
RETURN(RC_WMORE);
}
}
/* /*
* BIT STRING-specific processing. * BIT STRING-specific processing.
*/ */
...@@ -458,10 +472,8 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td, ...@@ -458,10 +472,8 @@ OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
consumed_myself, td->name, consumed_myself, td->name,
(type_type == _TT_GENERIC) ? (char *)st->buf : "", st->size); (type_type == _TT_GENERIC) ? (char *)st->buf : "", st->size);
rval.code = RC_OK;
rval.consumed = consumed_myself;
return rval; RETURN(RC_OK);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment