From: Pekka Riikonen Date: Sun, 8 Jul 2007 17:24:33 +0000 (+0000) Subject: Added support for allocating from the given stack with X-Git-Tag: 1.2.beta1~212 X-Git-Url: http://git.silcnet.org/gitweb/?a=commitdiff_plain;h=524dff836509afe72184a51bb55818377c3232e1;p=crypto.git Added support for allocating from the given stack with SILC_ASN1_ALLOC. Added support for returning value if SILC_ASN1_NULL was present or is encoded. Added support for getting the choice that was found with SILC_ASN1_CHOICE. --- diff --git a/lib/silcasn1/silcasn1.c b/lib/silcasn1/silcasn1.c index c1ec3bb4..b80a1c09 100644 --- a/lib/silcasn1/silcasn1.c +++ b/lib/silcasn1/silcasn1.c @@ -39,6 +39,7 @@ SilcAsn1 silc_asn1_alloc(SilcStack stack) return NULL; } + asn1->orig_stack = stack; asn1->stack1 = stack1; asn1->stack2 = silc_stack_alloc(0, stack); if (!asn1->stack2) { @@ -62,6 +63,8 @@ void silc_asn1_free(SilcAsn1 asn1) SilcBool silc_asn1_init(SilcAsn1 asn1, SilcStack stack) { + asn1->orig_stack = stack; + asn1->stack1 = silc_stack_alloc(0, stack); if (!asn1->stack1) return FALSE; @@ -193,7 +196,7 @@ SilcBool silc_asn1_dump(SilcAsn1 asn1, SilcBuffer src) } fprintf(stdout, "Type %s [%d]\n", - silc_asn1_tag_name(rtag), rtag); + silc_asn1_tag_name(rtag), (int)rtag); if (renc == SILC_BER_ENC_PRIMITIVE) len = len + rdata_len; diff --git a/lib/silcasn1/silcasn1.h b/lib/silcasn1/silcasn1.h index 6ee70bbb..304dd600 100644 --- a/lib/silcasn1/silcasn1.h +++ b/lib/silcasn1/silcasn1.h @@ -112,6 +112,20 @@ typedef struct SilcAsn1Object SilcAsn1Struct; * SILC_ASN1_EXPLICIT, 100, boolval), * SILC_ASN1_END); * + * + * // Decode optional value, with SILC_ASN1_OPTIONAL the type must be + * // a pointer so that NULL can be returned if the type is not present. + * SilcBool *val; + * + * silc_asn1_decode(asn1, src, + * SILC_ASN1_OPTS(SILC_ASN1_OPTIONAL), + * SILC_ASN1_BOOLEAN(&val), + * SILC_ASN1_END); + * + * // If val == NULL, the optional value was not present + * if (val == NULL) + * error; + * * SOURCE */ typedef enum { @@ -141,7 +155,10 @@ typedef enum { /* ASN.1 encoder/decoder options (bitmask). These can be given only with SILC_ASN1_OPTS macro at the start of encoding/decoding. */ - SILC_ASN1_ALLOC = 0x0400, /* Dynamically allocate results */ + SILC_ASN1_ALLOC = 0x0400, /* Dynamically allocate results, + or if stack was given to + silc_asn1_alloc, they are allocated + and consumed from the stack. */ SILC_ASN1_ACCUMUL = 0x0800, /* Accumulate memory for results, next call to silc_asn1_decode will not cancel old results. */ @@ -218,7 +235,9 @@ typedef enum { * * When this context is freed with silc_asn1_free all memory will be * freed, and all encoded ASN.1 buffers becomes invalid. Also all - * data that is returned by silc_asn1_decode function becomes invalid. + * data that is returned by silc_asn1_encode and silc_asn1_decode function + * becomes invalid, unless SILC_ASN1_ALLOC flag is used, in which case the + * memory is allocated from `stack' and the `stack' is consumed. * ***/ SilcAsn1 silc_asn1_alloc(SilcStack stack); @@ -290,11 +309,12 @@ void silc_asn1_uninit(SilcAsn1 asn1); * * If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then * the `dest' is dynamically allocated and caller must free it by itself. - * Alternatively if SILC_ASN1_ACCUMUL is given then memory is accumulated - * from `asn1' for `dest' and it is freed only when silc_asn1_free or - * silc_asn1_uninit is called. Next call to silc_asn1_encode will not - * cancel the previous result, but will accumulate more memory for new - * result. + * If the `stack' was given to silc_asn1_alloc, the SILC_ASN1_ALLOC will + * allocate from that stack and consume the stack. Alternatively if + * SILC_ASN1_ACCUMUL is given then memory is accumulated from `asn1' fo + * `dest' and it is freed only when silc_asn1_free or silc_asn1_uninit + * is called. Next call to silc_asn1_encode will not cancel the previous + * result, but will accumulate more memory for new result. * * The variable argument list is constructed by using various * macros, for example SILC_ASN1_SEQUENCE, etc. The variable argument @@ -352,13 +372,14 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...); * * If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then * all results are dynamically allocated and caller must free them by - * itself. Alternatively if SILC_ASN1_ACCUMUL is given then memory is - * accumulated from `asn1' for results and they are freed only when the - * silc_asn1_free or silc_asn1_uninit is called. Next calls to the - * silc_asn1_decode will NOT invalidate the old results, but will - * accumulate more memory for new results. If the SILC_ASN1_OPTS is not - * given at all then the default allocation method (decribed above) - * applies. + * itself. If the `stack' was given to silc_asn1_alloc, the SILC_ASN1_ALLOC + * will allocate from that stack and consume the stack. Alternatively if + * SILC_ASN1_ACCUMUL is given then memory is accumulated from `asn1' for + * results and they are freed only when the silc_asn1_free or + * silc_asn1_uninit is called. Next calls to the silc_asn1_decode will + * NOT invalidate the old results, but will accumulate more memory for new + * results. If the SILC_ASN1_OPTS is not given at all then the default + * allocation method (decribed above) applies. * * If caller needs to store the results even after `asn1' becomes invalid * then call must either use SILC_ASN1_ALLOC option or duplicate the @@ -631,27 +652,29 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * SYNOPSIS * * Decoding: - * SILC_ASN1_CHOICE + * SILC_ASN1_CHOICE(&chosen) * * DESCRIPTION * * Macro used to specify choices in decoding. The choice list must * be terminated with SILC_ASN1_END. There is no limit how many choices - * can be specified in the list. + * can be specified in the list. The `chosen' is SilcUInt32 and its + * value tells which of the choice was found. First choice in the list + * has value 1, second value 2, and so on. * * EXAMPLE * * // Decode timeval that is either UTC or generalized time * silc_asn1_decode(asn1, tree, * SILC_ASN1_SEQUENCE, - * SILC_ASN1_CHOICE, + * SILC_ASN1_CHOICE(&chosen), * SILC_ASN1_UTC_TIME(&timeval), * SILC_ASN1_GEN_TIME(&timeval), * SILC_ASN1_END, * SILC_ASN1_END, SILC_ASN1_END); * ***/ -#define SILC_ASN1_CHOICE SILC_ASN1_U0(CHOICE) +#define SILC_ASN1_CHOICE(x) SILC_ASN1_U1(CHOICE, x) /****f* silcasn1/SilcASN1API/SILC_ASN1_BOOLEAN * @@ -776,21 +799,25 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...); * * Encoding: * SILC_ASN1_NULL - * SILC_ASN1_NULL_T(opts, tag) + * SILC_ASN1_NULL_T(opts, tag, set) * * Decoding: * SILC_ASN1_NULL - * SILC_ASN1_NULL_T(opts, tag) + * SILC_ASN1_NULL_T(opts, tag, &set) * * DESCRIPTION * * Macro used to encode or decode null value. * - * The `opts' is SilcAsn1Options. The `tag' is a tag number. + * The `opts' is SilcAsn1Options. The `tag' is a tag number. In encoding + * `set' is SilcBool and if it is TRUE the NULL value will be encoded. If + * it is FALSE the SILC_ASN1_NULL will be ignored. In decoding the `set' + * is SilcBool and if it is TRUE the NULL value was present. This can be + * used to verify whether NULL was present if it is SILC_ASN1_OPTIONAL. * ***/ -#define SILC_ASN1_NULL SILC_ASN1_U0(NULL) -#define SILC_ASN1_NULL_T(o, t) SILC_ASN1_T0(NULL, 0, t) +#define SILC_ASN1_NULL(x) SILC_ASN1_U1(NULL, x) +#define SILC_ASN1_NULL_T(o, t, x) SILC_ASN1_T1(NULL, o, t, x) /****f* silcasn1/SilcASN1API/SILC_ASN1_OID * diff --git a/lib/silcasn1/silcasn1_decode.c b/lib/silcasn1/silcasn1_decode.c index 3030d07c..bcdd5e67 100644 --- a/lib/silcasn1/silcasn1_decode.c +++ b/lib/silcasn1/silcasn1_decode.c @@ -21,6 +21,8 @@ #include "silcasn1.h" #include "silcber.h" +#define SILC_ASN1_STACK(stack, asn1) stack ? stack : asn1->orig_stack + /************************** ASN.1 Decoder routines **************************/ /* Internal SEQUENCE OF and SET OF decoder. This is used only when decoding @@ -36,8 +38,8 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) SilcBuffer *retb; SilcUInt32 *retc, rtag; const unsigned char *rdata; - SilcUInt32 rdata_len, len = 0; - SilcBool found = FALSE, rindef; + SilcUInt32 rdata_len, len = 0, *choice_index = NULL; + SilcBool found = FALSE, rindef, chosen = FALSE; struct SilcAsn1SofStruct { SilcAsn1Tag type; @@ -62,10 +64,13 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) if (type == SILC_ASN1_TAG_CHOICE) { /* The sequence may consist of the following types. */ + choice_index = va_arg(asn1->ap, SilcUInt32 *); + *choice_index = 0; + type = va_arg(asn1->ap, SilcUInt32); assert(type != SILC_ASN1_END); while (type != SILC_ASN1_END) { - t = silc_smalloc(asn1->stack1, sizeof(*t)); + t = silc_smalloc(SILC_ASN1_STACK(asn1->stack1, asn1), sizeof(*t)); if (!t) goto out; t->type = type; @@ -78,7 +83,7 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) } } else { /* The sequence consists of this type. */ - t = silc_smalloc(asn1->stack1, sizeof(*t)); + t = silc_smalloc(SILC_ASN1_STACK(asn1->stack1, asn1), sizeof(*t)); if (!t) goto out; t->type = type; @@ -118,10 +123,14 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) found = FALSE; silc_list_start(types); while ((t = silc_list_get(types)) != SILC_LIST_END) { + if (choice_index && !chosen) + (*choice_index)++; + if (t->type != rtag) continue; - *retb = silc_srealloc(asn1->stack1, sizeof(**retb) * (*retc), *retb, + *retb = silc_srealloc(SILC_ASN1_STACK(asn1->stack1, asn1), + sizeof(**retb) * (*retc), *retb, sizeof(**retb) * (*retc + 1)); if (*retb == NULL) goto out; @@ -129,9 +138,10 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) SILC_LOG_DEBUG(("Decode %s [%d] from sequence of types", silc_asn1_tag_name(rtag), rtag)); - /* Data is duplicated only if SILC_ASN1_ALLOC flag is set */ + /* Data is duplicated only if SILC_ASN1_ALLOC flag is set, ie. + asn1->stack1 == NULL */ if (!asn1->stack1) - rdata = silc_memdup(rdata - len, rdata_len + len); + rdata = silc_smemdup(asn1->orig_stack, rdata - len, rdata_len + len); else rdata = rdata - len; rdata_len += len; @@ -140,6 +150,7 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) silc_buffer_set(&(*retb)[*retc], (unsigned char *)rdata, rdata_len); (*retc)++; found = TRUE; + chosen = TRUE; break; } @@ -158,7 +169,7 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) if (!asn1->stack1) { silc_list_start(types); while ((t = silc_list_get(types)) != SILC_LIST_END) - silc_free(t); + silc_sfree(asn1->orig_stack, t); } return ret; @@ -178,7 +189,8 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) } \ if (name == NULL) \ break; \ - *name = silc_scalloc(asn1->stack1, 1, sizeof(**name)); \ + *name = silc_scalloc(SILC_ASN1_STACK(stack1, asn1), \ + 1, sizeof(**name)); \ if (*name == NULL) \ break; \ } else { \ @@ -219,7 +231,7 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) #define SILC_ASN1_VA_FREE(opts, name) \ if ((opts) & SILC_ASN1_OPTIONAL) \ - silc_free(*name); + silc_sfree(SILC_ASN1_STACK(stack1, asn1), *name); /* Decodes string to UTF-8 string which is our internal representation of any string. */ @@ -230,7 +242,7 @@ static SilcBool silc_asn1_decoder_sof(SilcAsn1 asn1, SilcBuffer src) ret = FALSE; \ goto fail; \ } \ - *s = silc_smalloc(stack1, *s_len + 1); \ + *s = silc_smalloc(SILC_ASN1_STACK(stack1, asn1), *s_len + 1); \ if (*s) { \ silc_utf8_encode(rdata, rdata_len, (enc), *s, *s_len); \ (*s)[*s_len] = '\0'; \ @@ -254,8 +266,9 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, SilcBerEncoding renc; SilcUInt32 len = 0, rtag; SilcBool ret, indef, rindef, found = FALSE, choice = FALSE; + SilcBool choice_found = FALSE; const unsigned char *rdata; - SilcUInt32 rdata_len; + SilcUInt32 rdata_len, *choice_index = NULL; int i; #ifdef SILC_DEBUG @@ -335,6 +348,8 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, having OPTIONAL flag set, except that at the end one must have been found. */ if (type == SILC_ASN1_TAG_CHOICE) { + choice_index = va_arg(asn1->ap, SilcUInt32 *); + *choice_index = 0; choice = TRUE; SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts); opts |= SILC_ASN1_OPTIONAL; @@ -416,7 +431,8 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, the node */ SILC_ASN1_VAD(asn1, opts, SilcBufferStruct, node); - *node = silc_buffer_srealloc_size(stack1, *node, len + rdata_len); + *node = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), + *node, len + rdata_len); silc_buffer_put(*node, rdata - len, rdata_len + len); break; } @@ -426,7 +442,8 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, /* ANY_PRIMITIVE returns the raw data blob of any primitive type. */ SILC_ASN1_VAD(asn1, opts, SilcBufferStruct, prim); - *prim = silc_buffer_srealloc_size(stack1, *prim, rdata_len); + *prim = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), + *prim, rdata_len); silc_buffer_put(*prim, rdata, rdata_len); break; } @@ -442,8 +459,9 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts); /* Decode the sequence recursively */ - ret = silc_asn1_decoder(asn1, stack1, rtype, rtag, rclass, - ropts, src, depth + 1, FALSE); + ret = silc_asn1_decoder(asn1, SILC_ASN1_STACK(stack1, asn1), + rtype, rtag, rclass, ropts, src, + depth + 1, FALSE); if (!ret) goto fail; break; @@ -463,7 +481,7 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, goto fail; } - silc_mp_sinit(asn1->stack1, *intval); + silc_mp_sinit(SILC_ASN1_STACK(stack1, asn1), *intval); /* Check whether the integer is positive or negative */ if (rdata[0] & 0x80) { @@ -500,12 +518,12 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, goto fail; } - silc_stack_push(asn1->stack1, NULL); - silc_mp_sinit(asn1->stack1, &z); + silc_stack_push(SILC_ASN1_STACK(stack1, asn1), NULL); + silc_mp_sinit(SILC_ASN1_STACK(stack1, asn1), &z); silc_mp_bin2mp((unsigned char *)rdata, rdata_len, &z); *(*intval) = silc_mp_get_ui(&z); silc_mp_uninit(&z); - silc_stack_pop(asn1->stack1); + silc_stack_pop(SILC_ASN1_STACK(stack1, asn1)); break; } @@ -530,7 +548,8 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, silc_snprintf(tmpstr, sizeof(tmpstr) - 1, "%lu.%lu", (unsigned long)(rdata[0] & 0xff) / 40, (unsigned long)(rdata[0] & 0xff) % 40); - silc_buffer_sstrformat(asn1->stack1, &tmpb, tmpstr, SILC_STR_END); + silc_buffer_sstrformat(SILC_ASN1_STACK(stack1, asn1), + &tmpb, tmpstr, SILC_STR_END); /* Set rest of the OID values, each octet having 7 bits of the OID value with bit 8 set. An octet not having bit 8 set @@ -549,8 +568,10 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, oid |= rdata[i]; memset(tmpstr, 0, sizeof(tmpstr)); - silc_snprintf(tmpstr, sizeof(tmpstr) - 1, ".%lu", (unsigned long)oid); - silc_buffer_sstrformat(asn1->stack1, &tmpb, tmpstr, SILC_STR_END); + silc_snprintf(tmpstr, sizeof(tmpstr) - 1, ".%lu", + (unsigned long)oid); + silc_buffer_sstrformat(SILC_ASN1_STACK(stack1, asn1), + &tmpb, tmpstr, SILC_STR_END); } *oidstr = tmpb.head; @@ -585,18 +606,23 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, goto fail; } - *d = silc_smemdup(stack1, rdata + 1, rdata_len - 1); + *d = silc_smemdup(SILC_ASN1_STACK(stack1, asn1), + rdata + 1, rdata_len - 1); *d_len = (rdata_len - 1) * 8; break; } case SILC_ASN1_TAG_NULL: { + SILC_ASN1_VAD(asn1, opts, SilcBool, val); + /* Decode empty BER block */ if (rdata_len != 0) { SILC_LOG_DEBUG(("Malformed null value")); goto fail; } + + *(*val) = TRUE; break; } @@ -657,7 +683,7 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, goto fail; } - *s = silc_smemdup(stack1, rdata, rdata_len); + *s = silc_smemdup(SILC_ASN1_STACK(stack1, asn1), rdata, rdata_len); *s_len = rdata_len; break; } @@ -666,7 +692,7 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, { /* Octet string. Take data as is. */ SILC_ASN1_VAD_UCHAR(asn1, opts, unsigned char, s, s_len); - *s = silc_smemdup(stack1, rdata, rdata_len); + *s = silc_smemdup(SILC_ASN1_STACK(stack1, asn1), rdata, rdata_len); *s_len = rdata_len; break; } @@ -776,10 +802,17 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, if (!found) { /* No choices were found, error */ SILC_LOG_DEBUG(("Invalid ASN.1 choice: no choices present")); + *choice_index = 0; ret = FALSE; goto fail; } + if (!choice_found) { + (*choice_index)++; + SILC_LOG_DEBUG(("Found choice %s type, index %d", + silc_asn1_tag_name(rtype), *choice_index)); + } + /* Take next type and new BER object, choices are over */ choice = FALSE; SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts); @@ -796,10 +829,15 @@ silc_asn1_decoder(SilcAsn1 asn1, SilcStack stack1, SilcAsn1Tag type, } if (choice) { + if (!choice_found) + (*choice_index)++; + /* Even if the choice was found we must go through rest of the choices. */ if (found && len) { - SILC_LOG_DEBUG(("Found choice %s type", silc_asn1_tag_name(rtype))); + choice_found = TRUE; + SILC_LOG_DEBUG(("Found choice %s type, index %d", + silc_asn1_tag_name(rtype), *choice_index)); rdata_len = len = 0; } opts |= SILC_ASN1_OPTIONAL; @@ -833,7 +871,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...) SilcAsn1Options opts; SilcBerClass ber_class; SilcStackFrame frame1, frame2; - SilcStack stack1 = NULL, stack2 = NULL; + SilcStack stack1 = NULL, stack2 = NULL, orig; SilcBool ret; if (!asn1) @@ -841,6 +879,8 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...) va_start(asn1->ap, src); + orig = asn1->orig_stack; + /* Get the first arguments and call the decoder. */ SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts); if (!type) { @@ -859,6 +899,7 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...) stack2 = asn1->stack2; asn1->stack1 = NULL; asn1->stack2 = NULL; + asn1->orig_stack = orig; } if (o & SILC_ASN1_ACCUMUL) { @@ -916,6 +957,8 @@ SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...) asn1->stack2 = stack2; } + asn1->orig_stack = orig; + va_end(asn1->ap); return ret; diff --git a/lib/silcasn1/silcasn1_encode.c b/lib/silcasn1/silcasn1_encode.c index 11b963ec..f2cf80c7 100644 --- a/lib/silcasn1/silcasn1_encode.c +++ b/lib/silcasn1/silcasn1_encode.c @@ -22,6 +22,7 @@ #include "silcber.h" #define SILC_ASN1_BUFFER_FREE(b, stack) if (!stack) silc_buffer_purge(b); +#define SILC_ASN1_STACK(stack, asn1) stack ? stack : asn1->orig_stack /************************** ASN.1 Encoder routines **************************/ @@ -44,7 +45,7 @@ s[s_len] = '\0'; \ } \ len = silc_ber_encoded_len(tag, s_len, indef); \ - dest = silc_buffer_srealloc_size(stack1, dest, \ + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, \ silc_buffer_truelen(dest) + len); \ ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, \ tag, s, s_len, indef); \ @@ -147,7 +148,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Encode the explicit tag */ len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED, tag, buf.data, silc_buffer_len(&buf), FALSE); @@ -192,7 +193,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Now encode with implicit tagging */ len = silc_ber_encoded_len(tag, d_len, FALSE); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED, tag, d, d_len, FALSE); @@ -201,7 +202,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } else { /* Copy the data directly into the tree. */ len = silc_buffer_len(node); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); if (!dest) goto fail; @@ -219,7 +220,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Encode the primitive data */ len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, prim->data, silc_buffer_len(prim), FALSE); @@ -249,7 +250,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Encode the sequence */ len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED, tag, buf.data, silc_buffer_len(&buf), indef); @@ -288,7 +289,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Encode the integer */ len = silc_ber_encoded_len(tag, len, indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, buf.data, silc_buffer_len(&buf), FALSE); @@ -327,7 +328,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* Encode the integer */ len = silc_ber_encoded_len(tag, len, indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, buf.data, silc_buffer_len(&buf), FALSE); @@ -418,7 +419,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, buf.data, silc_buffer_len(&buf), FALSE); @@ -437,7 +438,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, assert(indef == FALSE); len = silc_ber_encoded_len(tag, 1, FALSE); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, val, 1, FALSE); @@ -468,7 +469,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, silc_buffer_push(&buf, 1); len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, buf.data, silc_buffer_len(&buf), indef); @@ -482,14 +483,21 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, case SILC_ASN1_TAG_NULL: { /* Encode empty BER block */ + SilcBool val = va_arg(asn1->ap, SilcUInt32); + assert(indef == FALSE); + + if (!val) + break; + len = silc_ber_encoded_len(tag, 0, FALSE); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, NULL, 0, FALSE); if (!ret) goto fail; + break; } @@ -507,7 +515,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } len = silc_ber_encoded_len(tag, strlen(timestr), indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, timestr, strlen(timestr), indef); @@ -530,7 +538,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } len = silc_ber_encoded_len(tag, strlen(timestr), indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, timestr, strlen(timestr), indef); @@ -554,7 +562,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } len = silc_ber_encoded_len(tag, d_len, indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, d, d_len, indef); @@ -570,7 +578,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32); len = silc_ber_encoded_len(tag, d_len, indef); - dest = silc_buffer_srealloc_size(stack1, dest, + dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, silc_buffer_truelen(dest) + len); ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, tag, d, d_len, indef); @@ -693,7 +701,7 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) SilcAsn1Options opts; SilcBerClass ber_class; SilcStackFrame frame1, frame2; - SilcStack stack1 = NULL; + SilcStack stack1 = NULL, orig; SilcBool ret; if (!asn1) @@ -701,6 +709,9 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) va_start(asn1->ap, dest); + orig = asn1->orig_stack; + asn1->orig_stack = NULL; + /* Get the first arguments and call the encoder. */ SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts); if (!type) { @@ -717,6 +728,7 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) that stack aware calls revert to normal allocation routines. */ stack1 = asn1->stack1; asn1->stack1 = NULL; + asn1->orig_stack = orig; } if (o & SILC_ASN1_ACCUMUL) { @@ -758,6 +770,8 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) if (stack1 && !asn1->stack1) asn1->stack1 = stack1; + asn1->orig_stack = orig; + va_end(asn1->ap); return ret; diff --git a/lib/silcasn1/silcasn1_i.h b/lib/silcasn1/silcasn1_i.h index bec2cd43..414ec2c9 100644 --- a/lib/silcasn1/silcasn1_i.h +++ b/lib/silcasn1/silcasn1_i.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2003 - 2006 Pekka Riikonen + Copyright (C) 2003 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,9 +26,10 @@ /* ASN.1 context */ struct SilcAsn1Object { - va_list ap; /* List of ASN.1 types given as argument */ + SilcStack orig_stack; /* Stack given to silc_asn1_alloc */ SilcStack stack1; /* Stack for encoder */ SilcStack stack2; /* Internal stack for encoding/decoding */ + va_list ap; /* List of ASN.1 types given as argument */ unsigned int accumul : 1; /* Accumulate memory from stack for result */ }; diff --git a/lib/silcasn1/tests/test_silcasn1.c b/lib/silcasn1/tests/test_silcasn1.c index b3c5e915..c6266e1e 100644 --- a/lib/silcasn1/tests/test_silcasn1.c +++ b/lib/silcasn1/tests/test_silcasn1.c @@ -48,10 +48,10 @@ int main(int argc, char **argv) SilcBufferStruct node, node2; SilcAsn1 asn1; SilcBool success = FALSE; - SilcBool val = TRUE; + SilcBool val = TRUE, nval; int i; - unsigned char *str; - SilcUInt32 str_len, tmpint; + unsigned char *str, buf[512]; + SilcUInt32 str_len, tmpint, choice; char tmp[32]; SilcRng rng; SilcMPInt mpint, mpint2; @@ -183,7 +183,10 @@ int main(int argc, char **argv) SILC_ASN1_SEQUENCE_T(SILC_ASN1_EXPLICIT, 9), SILC_ASN1_SEQUENCE_T(SILC_ASN1_INDEFINITE, 0), SILC_ASN1_BOOLEAN_T(0, 4, &val), - SILC_ASN1_BOOLEAN(&val), + SILC_ASN1_CHOICE(&choice), + SILC_ASN1_SHORT_INT(&tmpint), + SILC_ASN1_BOOLEAN(&val), + SILC_ASN1_END, SILC_ASN1_END, SILC_ASN1_END, SILC_ASN1_END, SILC_ASN1_END); @@ -193,6 +196,9 @@ int main(int argc, char **argv) } SILC_LOG_DEBUG(("Decoding success")); SILC_LOG_DEBUG(("Boolean val %d", val)); + SILC_LOG_DEBUG(("Choice index %d", choice)); + if (choice != 2) + goto out; printf("\n"); @@ -607,7 +613,7 @@ int main(int argc, char **argv) SILC_ASN1_BOOLEAN_T(0, 100, val), SILC_ASN1_END, SILC_ASN1_SEQUENCE, - SILC_ASN1_NULL, + SILC_ASN1_NULL(TRUE), SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 0, val), SILC_ASN1_OCTET_STRING("foobar", 6), SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE, 43, val), @@ -634,7 +640,7 @@ int main(int argc, char **argv) SILC_ASN1_BOOLEAN_T(0, 100, &val), SILC_ASN1_END, SILC_ASN1_SEQUENCE, - SILC_ASN1_NULL, + SILC_ASN1_NULL(&nval), SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 0, &val), SILC_ASN1_OCTET_STRING(&str, &str_len), SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE, 43, &val), @@ -648,16 +654,17 @@ int main(int argc, char **argv) } SILC_LOG_DEBUG(("Decoding success")); SILC_LOG_DEBUG(("Boolean val %d", val)); + SILC_LOG_DEBUG(("NULL is present %s", nval ? "yes" : "no")); SILC_LOG_DEBUG(("Ooctet-string %s, len %d", str, str_len)); printf("\n"); memset(&node, 0, sizeof(node)); SILC_LOG_DEBUG(("Encoding ASN.1 tree 10 (INTEGER)")); - str = silc_rng_get_rn_data(rng, 256); + silc_rng_get_rn_data(rng, 256, buf, sizeof(buf)); silc_mp_init(&mpint); silc_mp_init(&mpint2); - silc_mp_bin2mp(str, 256, &mpint); + silc_mp_bin2mp(buf, 256, &mpint); success = silc_asn1_encode(asn1, &node, SILC_ASN1_INT(&mpint),