X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=crypto%2Fasn1%2Ftasn_enc.c;h=ed892e2cb2f58e86653b50d6ce9aaa95cc46688b;hb=927a28ba3b58210dd83f5ace7f29fbf7b2caf05b;hp=4b2784987a86991328fa2894a392509e38fffda5;hpb=06db4253e2eb1208b60b5107c6a02d385a0e2129;p=openssl.git diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c index 4b2784987a..ed892e2cb2 100644 --- a/crypto/asn1/tasn_enc.c +++ b/crypto/asn1/tasn_enc.c @@ -3,7 +3,7 @@ * project 2000. */ /* ==================================================================== - * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * Copyright (c) 2000-2004 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,88 +58,120 @@ #include +#include +#include "cryptlib.h" #include #include #include -static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); -static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *seq, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int isset); +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, + int tag, int aclass); +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass); +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, + int tag, int aclass); +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags); + +/* Top level i2d equivalents: the 'ndef' variant instructs the encoder + * to use indefinite length constructed encoding, where appropriate + */ + +int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); + } + +int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, 0); + } -/* Encode an ASN1 item, this is compatible with the +/* Encode an ASN1 item, this is use by the * standard 'i2d' function. 'out' points to - * a buffer to output the data to, in future we will - * have more advanced versions that can output data - * a piece at a time and this will simply be a special - * case. + * a buffer to output the data to. * * The new i2d has one additional feature. If the output * buffer is NULL (i.e. *out == NULL) then a buffer is * allocated and populated with the encoding. */ - -int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) -{ - if(out && !*out) { +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags) + { + if (out && !*out) + { unsigned char *p, *buf; int len; - len = ASN1_item_ex_i2d(&val, NULL, it, -1, 0); - if(len <= 0) return len; + len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); + if (len <= 0) + return len; buf = OPENSSL_malloc(len); - if(!buf) return -1; + if (!buf) + return -1; p = buf; - ASN1_item_ex_i2d(&val, &p, it, -1, 0); + ASN1_item_ex_i2d(&val, &p, it, -1, flags); *out = buf; return len; + } + + return ASN1_item_ex_i2d(&val, out, it, -1, flags); } - - return ASN1_item_ex_i2d(&val, out, it, -1, 0); -} /* Encode an item, taking care of IMPLICIT tagging (if any). * This function performs the normal item handling: it can be * used in external types. */ -int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) -{ +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { const ASN1_TEMPLATE *tt = NULL; unsigned char *p = NULL; - int i, seqcontlen, seqlen; - ASN1_STRING *strtmp; + int i, seqcontlen, seqlen, ndef = 1; const ASN1_COMPAT_FUNCS *cf; const ASN1_EXTERN_FUNCS *ef; const ASN1_AUX *aux = it->funcs; - ASN1_aux_cb *asn1_cb; - if((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) return 0; - if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; - else asn1_cb = 0; + ASN1_aux_cb *asn1_cb = 0; + + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + return 0; - switch(it->itype) { + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + + switch(it->itype) + { case ASN1_ITYPE_PRIMITIVE: - if(it->templates) - return ASN1_template_i2d(pval, out, it->templates); + if (it->templates) + return asn1_template_ex_i2d(pval, out, it->templates, + tag, aclass); return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); break; case ASN1_ITYPE_MSTRING: - strtmp = (ASN1_STRING *)*pval; - return asn1_i2d_ex_primitive(pval, out, it, -1, 0); + return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); case ASN1_ITYPE_CHOICE: - if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) return 0; i = asn1_get_choice_selector(pval, it); - if((i >= 0) && (i < it->tcount)) { + if ((i >= 0) && (i < it->tcount)) + { ASN1_VALUE **pchval; const ASN1_TEMPLATE *chtt; chtt = it->templates + i; pchval = asn1_get_field_ptr(pval, chtt); - return ASN1_template_i2d(pchval, out, chtt); - } + return asn1_template_ex_i2d(pchval, out, chtt, + -1, aclass); + } /* Fixme: error condition if selector out of range */ - if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) return 0; break; @@ -151,136 +183,236 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it case ASN1_ITYPE_COMPAT: /* old style hackery... */ cf = it->funcs; - if(out) p = *out; + if (out) + p = *out; i = cf->asn1_i2d(*pval, out); /* Fixup for IMPLICIT tag: note this messes up for tags > 30, * but so did the old code. Tags > 30 are very rare anyway. */ - if(out && (tag != -1)) + if (out && (tag != -1)) *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); return i; + case ASN1_ITYPE_NDEF_SEQUENCE: + /* Use indefinite length constructed if requested */ + if (aclass & ASN1_TFLG_NDEF) ndef = 2; + /* fall through */ + case ASN1_ITYPE_SEQUENCE: i = asn1_enc_restore(&seqcontlen, out, pval, it); /* An error occurred */ - if(i < 0) return 0; + if (i < 0) + return 0; /* We have a valid cached encoding... */ - if(i > 0) return seqcontlen; + if (i > 0) + return seqcontlen; /* Otherwise carry on */ seqcontlen = 0; /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ - if(tag == -1) { + if (tag == -1) + { tag = V_ASN1_SEQUENCE; - aclass = V_ASN1_UNIVERSAL; - } - if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) + /* Retain any other flags in aclass */ + aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) + | V_ASN1_UNIVERSAL; + } + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) return 0; /* First work out sequence content length */ - for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) { + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); - if(!seqtt) return 0; + if (!seqtt) + return 0; pseqval = asn1_get_field_ptr(pval, seqtt); /* FIXME: check for errors in enhanced version */ - /* FIXME: special handling of indefinite length encoding */ - seqcontlen += ASN1_template_i2d(pseqval, NULL, seqtt); - } - seqlen = ASN1_object_size(1, seqcontlen, tag); - if(!out) return seqlen; + seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, + -1, aclass); + } + + seqlen = ASN1_object_size(ndef, seqcontlen, tag); + if (!out) + return seqlen; /* Output SEQUENCE header */ - ASN1_put_object(out, 1, seqcontlen, tag, aclass); - for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) { + ASN1_put_object(out, ndef, seqcontlen, tag, aclass); + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { const ASN1_TEMPLATE *seqtt; ASN1_VALUE **pseqval; seqtt = asn1_do_adb(pval, tt, 1); - if(!seqtt) return 0; + if (!seqtt) + return 0; pseqval = asn1_get_field_ptr(pval, seqtt); /* FIXME: check for errors in enhanced version */ - ASN1_template_i2d(pseqval, out, seqtt); - } - if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) + asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); + } + if (ndef == 2) + ASN1_put_eoc(out); + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) return 0; return seqlen; default: return 0; - } + + } return 0; -} + } -int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt) -{ - int i, ret, flags, aclass; +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt) + { + return asn1_template_ex_i2d(pval, out, tt, -1, 0); + } + +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, int tag, int iclass) + { + int i, ret, flags, ttag, tclass, ndef; flags = tt->flags; - aclass = flags & ASN1_TFLG_TAG_CLASS; - if(flags & ASN1_TFLG_SK_MASK) { + /* Work out tag and class to use: tagging may come + * either from the template or the arguments, not both + * because this would create ambiguity. Additionally + * the iclass argument may contain some additional flags + * which should be noted and passed down to other levels. + */ + if (flags & ASN1_TFLG_TAG_MASK) + { + /* Error if argument and template tagging */ + if (tag != -1) + /* FIXME: error code here */ + return -1; + /* Get tagging from template */ + ttag = tt->tag; + tclass = flags & ASN1_TFLG_TAG_CLASS; + } + else if (tag != -1) + { + /* No template tagging, get from arguments */ + ttag = tag; + tclass = iclass & ASN1_TFLG_TAG_CLASS; + } + else + { + ttag = -1; + tclass = 0; + } + /* + * Remove any class mask from iflag. + */ + iclass &= ~ASN1_TFLG_TAG_CLASS; + + /* At this point 'ttag' contains the outer tag to use, + * 'tclass' is the class and iclass is any flags passed + * to this function. + */ + + /* if template and arguments require ndef, use it */ + if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) + ndef = 2; + else ndef = 1; + + if (flags & ASN1_TFLG_SK_MASK) + { /* SET OF, SEQUENCE OF */ STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; int isset, sktag, skaclass; int skcontlen, sklen; ASN1_VALUE *skitem; - if(!*pval) return 0; - if(flags & ASN1_TFLG_SET_OF) { + + if (!*pval) + return 0; + + if (flags & ASN1_TFLG_SET_OF) + { isset = 1; /* 2 means we reorder */ - if(flags & ASN1_TFLG_SEQUENCE_OF) isset = 2; - } else isset = 0; - /* First work out inner tag value */ - if(flags & ASN1_TFLG_IMPTAG) { - sktag = tt->tag; - skaclass = aclass; - } else { + if (flags & ASN1_TFLG_SEQUENCE_OF) + isset = 2; + } + else isset = 0; + + /* Work out inner tag value: if EXPLICIT + * or no tagging use underlying type. + */ + if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) + { + sktag = ttag; + skaclass = tclass; + } + else + { skaclass = V_ASN1_UNIVERSAL; - if(isset) sktag = V_ASN1_SET; + if (isset) + sktag = V_ASN1_SET; else sktag = V_ASN1_SEQUENCE; - } - /* Now work out length of items */ + } + + /* Determine total length of items */ skcontlen = 0; - for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) { + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { skitem = sk_ASN1_VALUE_value(sk, i); - skcontlen += ASN1_item_ex_i2d(&skitem, NULL, tt->item, -1, 0); - } - sklen = ASN1_object_size(1, skcontlen, sktag); + skcontlen += ASN1_item_ex_i2d(&skitem, NULL, + ASN1_ITEM_ptr(tt->item), + -1, iclass); + } + sklen = ASN1_object_size(ndef, skcontlen, sktag); /* If EXPLICIT need length of surrounding tag */ - if(flags & ASN1_TFLG_EXPTAG) - ret = ASN1_object_size(1, sklen, tt->tag); + if (flags & ASN1_TFLG_EXPTAG) + ret = ASN1_object_size(ndef, sklen, ttag); else ret = sklen; - if(!out) return ret; + if (!out) + return ret; /* Now encode this lot... */ /* EXPLICIT tag */ - if(flags & ASN1_TFLG_EXPTAG) - ASN1_put_object(out, 1, sklen, tt->tag, aclass); + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_object(out, ndef, sklen, ttag, tclass); /* SET or SEQUENCE and IMPLICIT tag */ - ASN1_put_object(out, 1, skcontlen, sktag, skaclass); - /* And finally the stuff itself */ - asn1_set_seq_out(sk, out, skcontlen, tt->item, isset); + ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); + /* And the stuff itself */ + asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), + isset, iclass); + if (ndef == 2) + { + ASN1_put_eoc(out); + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_eoc(out); + } return ret; - } - - if(flags & ASN1_TFLG_EXPTAG) { + } + + if (flags & ASN1_TFLG_EXPTAG) + { /* EXPLICIT tagging */ /* Find length of tagged item */ - i = ASN1_item_ex_i2d(pval, NULL, tt->item, -1, 0); - if(!i) return 0; + i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (!i) + return 0; /* Find length of EXPLICIT tag */ - ret = ASN1_object_size(1, i, tt->tag); - if(out) { + ret = ASN1_object_size(ndef, i, ttag); + if (out) + { /* Output tag and item */ - ASN1_put_object(out, 1, i, tt->tag, aclass); - ASN1_item_ex_i2d(pval, out, tt->item, -1, 0); - } + ASN1_put_object(out, ndef, i, ttag, tclass); + ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (ndef == 2) + ASN1_put_eoc(out); + } return ret; - } - if(flags & ASN1_TFLG_IMPTAG) { - /* IMPLICIT tagging */ - return ASN1_item_ex_i2d(pval, out, tt->item, tt->tag, aclass); - } - /* Nothing special: treat as normal */ - return ASN1_item_ex_i2d(pval, out, tt->item, -1, 0); + } + + /* Either normal or IMPLICIT tagging: combine class and flags */ + return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + ttag, tclass | iclass); + } /* Temporary structure used to hold DER encoding of items for SET OF */ @@ -292,72 +424,90 @@ typedef struct { } DER_ENC; static int der_cmp(const void *a, const void *b) -{ + { const DER_ENC *d1 = a, *d2 = b; int cmplen, i; cmplen = (d1->length < d2->length) ? d1->length : d2->length; i = memcmp(d1->data, d2->data, cmplen); - if(i) return i; + if (i) + return i; return d1->length - d2->length; -} + } /* Output the content octets of SET OF or SEQUENCE OF */ -static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int do_sort) -{ +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass) + { int i; ASN1_VALUE *skitem; - unsigned char *tmpdat, *p; - DER_ENC *derlst, *tder; - if(do_sort) { + unsigned char *tmpdat = NULL, *p = NULL; + DER_ENC *derlst = NULL, *tder; + if (do_sort) + { /* Don't need to sort less than 2 items */ - if(sk_ASN1_VALUE_num(sk) < 2) do_sort = 0; - else { - derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) * sizeof(*derlst)); + if (sk_ASN1_VALUE_num(sk) < 2) + do_sort = 0; + else + { + derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) + * sizeof(*derlst)); tmpdat = OPENSSL_malloc(skcontlen); - if(!derlst || !tmpdat) return 0; + if (!derlst || !tmpdat) + return 0; + } } - } /* If not sorting just output each item */ - if(!do_sort) { - for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) { + if (!do_sort) + { + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { skitem = sk_ASN1_VALUE_value(sk, i); - ASN1_item_i2d(skitem, out, item); - } + ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); + } return 1; - } + } p = tmpdat; + /* Doing sort: build up a list of each member's DER encoding */ - for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { skitem = sk_ASN1_VALUE_value(sk, i); tder->data = p; - tder->length = ASN1_item_i2d(skitem, &p, item); + tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); tder->field = skitem; - } + } + /* Now sort them */ qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); /* Output sorted DER encoding */ p = *out; - for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { memcpy(p, tder->data, tder->length); p += tder->length; - } + } *out = p; /* If do_sort is 2 then reorder the STACK */ - if(do_sort == 2) { - for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) - sk_ASN1_VALUE_set(sk, i, tder->field); - } + if (do_sort == 2) + { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); + i++, tder++) + (void)sk_ASN1_VALUE_set(sk, i, tder->field); + } OPENSSL_free(derlst); OPENSSL_free(tmpdat); return 1; -} + } -static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) -{ +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { int len; int utype; int usetag; + int ndef = 0; utype = it->utype; @@ -373,33 +523,48 @@ static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const A * because the call to asn1_ex_i2c() could change * utype. */ - if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || + if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) usetag = 0; else usetag = 1; /* -1 means omit type */ - if(len == -1) return 0; + if (len == -1) + return 0; + + /* -2 return is special meaning use ndef */ + if (len == -2) + { + ndef = 2; + len = 0; + } /* If not implicitly tagged get tag from underlying type */ - if(tag == -1) tag = utype; + if (tag == -1) tag = utype; /* Output tag+length followed by content octets */ - if(out) { - if(usetag) ASN1_put_object(out, 0, len, tag, aclass); + if (out) + { + if (usetag) + ASN1_put_object(out, ndef, len, tag, aclass); asn1_ex_i2c(pval, *out, &utype, it); - *out += len; - } + if (ndef) + ASN1_put_eoc(out); + else + *out += len; + } - if(usetag) return ASN1_object_size(0, len, tag); + if (usetag) + return ASN1_object_size(ndef, len, tag); return len; -} + } /* Produce content octets from a structure */ -int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ITEM *it) -{ +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, + const ASN1_ITEM *it) + { ASN1_BOOLEAN *tbool = NULL; ASN1_STRING *strtmp; ASN1_OBJECT *otmp; @@ -408,28 +573,36 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ int len; const ASN1_PRIMITIVE_FUNCS *pf; pf = it->funcs; - if(pf && pf->prim_i2c) return pf->prim_i2c(pval, cout, putype, it); + if (pf && pf->prim_i2c) + return pf->prim_i2c(pval, cout, putype, it); /* Should type be omitted? */ - if((it->itype != ASN1_ITYPE_PRIMITIVE) || (it->utype != V_ASN1_BOOLEAN)) { - if(!*pval) return -1; - } + if ((it->itype != ASN1_ITYPE_PRIMITIVE) + || (it->utype != V_ASN1_BOOLEAN)) + { + if (!*pval) return -1; + } - if(it->itype == ASN1_ITYPE_MSTRING) { + if (it->itype == ASN1_ITYPE_MSTRING) + { /* If MSTRING type set the underlying type */ strtmp = (ASN1_STRING *)*pval; utype = strtmp->type; *putype = utype; - } else if(it->utype == V_ASN1_ANY) { + } + else if (it->utype == V_ASN1_ANY) + { /* If ANY set type and pointer to value */ ASN1_TYPE *typ; typ = (ASN1_TYPE *)*pval; utype = typ->type; *putype = utype; pval = (ASN1_VALUE **)&typ->value.ptr; - } else utype = *putype; + } + else utype = *putype; - switch(utype) { + switch(utype) + { case V_ASN1_OBJECT: otmp = (ASN1_OBJECT *)*pval; cont = otmp->data; @@ -443,17 +616,24 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ case V_ASN1_BOOLEAN: tbool = (ASN1_BOOLEAN *)pval; - if(*tbool == -1) return -1; - /* Default handling if value == size field then omit */ - if(*tbool && (it->size > 0)) return -1; - if(!*tbool && !it->size) return -1; + if (*tbool == -1) + return -1; + if (it->utype != V_ASN1_ANY) + { + /* Default handling if value == size field then omit */ + if (*tbool && (it->size > 0)) + return -1; + if (!*tbool && !it->size) + return -1; + } c = (unsigned char)*tbool; cont = &c; len = 1; break; case V_ASN1_BIT_STRING: - return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, cout ? &cout : NULL); + return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, + cout ? &cout : NULL); break; case V_ASN1_INTEGER: @@ -463,7 +643,8 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ /* These are all have the same content format * as ASN1_INTEGER */ - return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); + return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, + cout ? &cout : NULL); break; case V_ASN1_OCTET_STRING: @@ -485,12 +666,25 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ default: /* All based on ASN1_STRING and handled the same */ strtmp = (ASN1_STRING *)*pval; + /* Special handling for NDEF */ + if ((it->size == ASN1_TFLG_NDEF) + && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) + { + if (cout) + { + strtmp->data = cout; + strtmp->length = 0; + } + /* Special return code */ + return -2; + } cont = strtmp->data; len = strtmp->length; break; - } - if(cout && len) memcpy(cout, cont, len); + } + if (cout && len) + memcpy(cout, cont, len); return len; -} + }