#include <stddef.h>
+#include <string.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/objects.h>
switch(it->itype) {
case ASN1_ITYPE_PRIMITIVE:
- if(it->templates)
+ if(it->templates) {
+ /* tagging or OPTIONAL is currently illegal on an item template
+ * because the flags can't get passed down. In practice this isn't
+ * a problem: we include the relevant flags from the item template
+ * in the template itself.
+ */
+ if ((tag != -1) || opt) {
+ ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
+ goto err;
+ }
return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx);
+ }
return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx);
break;
if(tag != -1) {
p = *in;
imphack = *p;
- *p = (*p & V_ASN1_CONSTRUCTED) | it->utype;
+ *p = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype);
}
ptmpval = cf->asn1_d2i(pval, in, len);
case ASN1_ITYPE_CHOICE:
if(asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))
goto auxerr;
+
+ /* Allocate structure */
+ if(!*pval) {
+ if(!ASN1_item_ex_new(pval, it)) {
+ ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ }
/* CHOICE type, try each possibility in turn */
pchval = NULL;
p = *in;
for(i = 0, tt=it->templates; i < it->tcount; i++, tt++) {
+ pchptr = asn1_get_field_ptr(pval, tt);
/* We mark field as OPTIONAL so its absence
* can be recognised.
*/
- ret = asn1_template_ex_d2i(&pchval, &p, len, tt, 1, ctx);
+ ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
/* If field not present, try the next one */
if(ret == -1) continue;
/* If positive return, read OK, break loop */
/* Otherwise must be an ASN1 parsing error */
errtt = tt;
ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
- return 0;
+ goto err;
}
/* Did we fall off the end without reading anything? */
if(i == it->tcount) {
/* If OPTIONAL, this is OK */
- if(opt) return -1;
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);
- return 0;
- }
- /* Otherwise we got a match, allocate structure and populate it */
- if(!*pval) {
- if(!ASN1_item_ex_new(pval, it)) {
- errtt = tt;
- ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
- return 0;
+ if(opt) {
+ /* Free and zero it */
+ ASN1_item_ex_free(pval, it);
+ return -1;
}
+ ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);
+ goto err;
}
- pchptr = asn1_get_field_ptr(pval, tt);
- *pchptr = pchval;
asn1_set_choice_selector(pval, i, it);
*in = p;
if(asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))
* it increases efficiency in some cases.
*/
if(i == (it->tcount - 1)) isopt = 0;
- else isopt = seqtt->flags & ASN1_TFLG_OPTIONAL;
+ else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
/* attempt to read in field, allowing each to be OPTIONAL */
ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
if(!ret) {
ASN1_VALUE *vtmp;
while(sk_num(sktmp) > 0) {
vtmp = (ASN1_VALUE *)sk_pop(sktmp);
- ASN1_item_ex_free(&vtmp, tt->item);
+ ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item));
}
}
break;
}
skfield = NULL;
- if(!ASN1_item_ex_d2i(&skfield, &p, len, tt->item, -1, 0, 0, ctx)) {
+ if(!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err;
}
}
} else if(flags & ASN1_TFLG_IMPTAG) {
/* IMPLICIT tagging */
- ret = ASN1_item_ex_d2i(val, &p, len, tt->item, tt->tag, aclass, opt, ctx);
+ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
if(!ret) {
ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err;
} else if(ret == -1) return -1;
} else {
/* Nothing special */
- ret = ASN1_item_ex_d2i(val, &p, len, tt->item, -1, 0, opt, ctx);
+ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx);
if(!ret) {
ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
goto err;
cont = *in;
/* If indefinite length constructed find the real end */
if(inf) {
- asn1_collect(NULL, &p, plen, inf, -1, -1);
+ if(!asn1_collect(NULL, &p, plen, inf, -1, -1)) goto err;
len = p - cont;
} else {
len = p - cont + plen;
* internally irrespective of the type. So instead just check
* for UNIVERSAL class and ignore the tag.
*/
- asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL);
- cont = (unsigned char *)buf.data;
+ if(!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL)) goto err;
len = buf.length;
+ /* Append a final null to string */
+ if(!BUF_MEM_grow(&buf, len + 1)) {
+ ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ buf.data[len] = 0;
+ cont = (unsigned char *)buf.data;
free_cont = 1;
} else {
cont = p;
ASN1_TYPE *typ = NULL;
int ret = 0;
const ASN1_PRIMITIVE_FUNCS *pf;
+ ASN1_INTEGER **tint;
pf = it->funcs;
if(pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
/* If ANY type clear type and set pointer to internal value */
if(!*pval) {
typ = ASN1_TYPE_new();
*pval = (ASN1_VALUE *)typ;
- } else typ = (ASN1_TYPE *)pval;
+ } else typ = (ASN1_TYPE *)*pval;
if(utype != typ->type) ASN1_TYPE_set(typ, utype, NULL);
pval = (ASN1_VALUE **)&typ->value.ptr;
}
case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
case V_ASN1_NEG_ENUMERATED:
- if(!c2i_ASN1_INTEGER((ASN1_INTEGER **)pval, &cont, len)) goto err;
+ tint = (ASN1_INTEGER **)pval;
+ if(!c2i_ASN1_INTEGER(tint, &cont, len)) goto err;
+ /* Fixup type to match the expected form */
+ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
break;
case V_ASN1_OCTET_STRING:
ctx->ptag = ptag;
ctx->hdrlen = p - q;
ctx->valid = 1;
- }
- /* If definite length, length + header can't exceed total
- * amount of data available.
- */
- if(!(i & 1) && ((plen + ctx->hdrlen) > len)) {
- ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG);
- asn1_tlc_clear(ctx);
- return 0;
+ /* If definite length, length + header can't exceed total
+ * amount of data available.
+ */
+ if(!(i & 1) && ((plen + ctx->hdrlen) > len)) {
+ ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG);
+ asn1_tlc_clear(ctx);
+ return 0;
+ }
}
}