Path: blob/main/crypto/heimdal/lib/asn1/gen_decode.c
34878 views
/*1* Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "gen_locl.h"34#include "lex.h"3536RCSID("$Id$");3738static void39decode_primitive (const char *typename, const char *name, const char *forwstr)40{41#if 042fprintf (codefile,43"e = decode_%s(p, len, %s, &l);\n"44"%s;\n",45typename,46name,47forwstr);48#else49fprintf (codefile,50"e = der_get_%s(p, len, %s, &l);\n"51"if(e) %s;\np += l; len -= l; ret += l;\n",52typename,53name,54forwstr);55#endif56}5758static void59find_tag (const Type *t,60Der_class *cl, Der_type *ty, unsigned *tag)61{62switch (t->type) {63case TBitString:64*cl = ASN1_C_UNIV;65*ty = PRIM;66*tag = UT_BitString;67break;68case TBoolean:69*cl = ASN1_C_UNIV;70*ty = PRIM;71*tag = UT_Boolean;72break;73case TChoice:74errx(1, "Cannot have recursive CHOICE");75case TEnumerated:76*cl = ASN1_C_UNIV;77*ty = PRIM;78*tag = UT_Enumerated;79break;80case TGeneralString:81*cl = ASN1_C_UNIV;82*ty = PRIM;83*tag = UT_GeneralString;84break;85case TTeletexString:86*cl = ASN1_C_UNIV;87*ty = PRIM;88*tag = UT_TeletexString;89break;90case TGeneralizedTime:91*cl = ASN1_C_UNIV;92*ty = PRIM;93*tag = UT_GeneralizedTime;94break;95case TIA5String:96*cl = ASN1_C_UNIV;97*ty = PRIM;98*tag = UT_IA5String;99break;100case TInteger:101*cl = ASN1_C_UNIV;102*ty = PRIM;103*tag = UT_Integer;104break;105case TNull:106*cl = ASN1_C_UNIV;107*ty = PRIM;108*tag = UT_Null;109break;110case TOID:111*cl = ASN1_C_UNIV;112*ty = PRIM;113*tag = UT_OID;114break;115case TOctetString:116*cl = ASN1_C_UNIV;117*ty = PRIM;118*tag = UT_OctetString;119break;120case TPrintableString:121*cl = ASN1_C_UNIV;122*ty = PRIM;123*tag = UT_PrintableString;124break;125case TSequence:126case TSequenceOf:127*cl = ASN1_C_UNIV;128*ty = CONS;129*tag = UT_Sequence;130break;131case TSet:132case TSetOf:133*cl = ASN1_C_UNIV;134*ty = CONS;135*tag = UT_Set;136break;137case TTag:138*cl = t->tag.tagclass;139*ty = is_primitive_type(t->subtype->type) ? PRIM : CONS;140*tag = t->tag.tagvalue;141break;142case TType:143if ((t->symbol->stype == Stype && t->symbol->type == NULL)144|| t->symbol->stype == SUndefined) {145lex_error_message("%s is imported or still undefined, "146" can't generate tag checking data in CHOICE "147"without this information",148t->symbol->name);149exit(1);150}151find_tag(t->symbol->type, cl, ty, tag);152return;153case TUTCTime:154*cl = ASN1_C_UNIV;155*ty = PRIM;156*tag = UT_UTCTime;157break;158case TUTF8String:159*cl = ASN1_C_UNIV;160*ty = PRIM;161*tag = UT_UTF8String;162break;163case TBMPString:164*cl = ASN1_C_UNIV;165*ty = PRIM;166*tag = UT_BMPString;167break;168case TUniversalString:169*cl = ASN1_C_UNIV;170*ty = PRIM;171*tag = UT_UniversalString;172break;173case TVisibleString:174*cl = ASN1_C_UNIV;175*ty = PRIM;176*tag = UT_VisibleString;177break;178default:179abort();180}181}182183static void184range_check(const char *name,185const char *length,186const char *forwstr,187struct range *r)188{189if (r->min == r->max + 2 || r->min < r->max)190fprintf (codefile,191"if ((%s)->%s > %" PRId64 ") {\n"192"e = ASN1_MAX_CONSTRAINT; %s;\n"193"}\n",194name, length, r->max, forwstr);195if (r->min - 1 == r->max || r->min < r->max)196fprintf (codefile,197"if ((%s)->%s < %" PRId64 ") {\n"198"e = ASN1_MIN_CONSTRAINT; %s;\n"199"}\n",200name, length, r->min, forwstr);201if (r->max == r->min)202fprintf (codefile,203"if ((%s)->%s != %" PRId64 ") {\n"204"e = ASN1_EXACT_CONSTRAINT; %s;\n"205"}\n",206name, length, r->min, forwstr);207}208209static int210decode_type (const char *name, const Type *t, int optional,211const char *forwstr, const char *tmpstr, const char *dertype,212unsigned int depth)213{214switch (t->type) {215case TType: {216if (optional)217fprintf(codefile,218"%s = calloc(1, sizeof(*%s));\n"219"if (%s == NULL) %s;\n",220name, name, name, forwstr);221fprintf (codefile,222"e = decode_%s(p, len, %s, &l);\n",223t->symbol->gen_name, name);224if (optional) {225fprintf (codefile,226"if(e) {\n"227"free(%s);\n"228"%s = NULL;\n"229"} else {\n"230"p += l; len -= l; ret += l;\n"231"}\n",232name, name);233} else {234fprintf (codefile,235"if(e) %s;\n",236forwstr);237fprintf (codefile,238"p += l; len -= l; ret += l;\n");239}240break;241}242case TInteger:243if(t->members) {244fprintf(codefile,245"{\n"246"int enumint;\n");247decode_primitive ("integer", "&enumint", forwstr);248fprintf(codefile,249"*%s = enumint;\n"250"}\n",251name);252} else if (t->range == NULL) {253decode_primitive ("heim_integer", name, forwstr);254} else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) {255decode_primitive ("integer64", name, forwstr);256} else if (t->range->min >= 0 && t->range->max > UINT_MAX) {257decode_primitive ("unsigned64", name, forwstr);258} else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) {259decode_primitive ("integer", name, forwstr);260} else if (t->range->min >= 0 && t->range->max <= UINT_MAX) {261decode_primitive ("unsigned", name, forwstr);262} else263errx(1, "%s: unsupported range %" PRId64 " -> %" PRId64,264name, t->range->min, t->range->max);265break;266case TBoolean:267decode_primitive ("boolean", name, forwstr);268break;269case TEnumerated:270decode_primitive ("enumerated", name, forwstr);271break;272case TOctetString:273if (dertype) {274fprintf(codefile,275"if (%s == CONS) {\n",276dertype);277decode_primitive("octet_string_ber", name, forwstr);278fprintf(codefile,279"} else {\n");280}281decode_primitive ("octet_string", name, forwstr);282if (dertype)283fprintf(codefile, "}\n");284if (t->range)285range_check(name, "length", forwstr, t->range);286break;287case TBitString: {288Member *m;289int pos = 0;290291if (ASN1_TAILQ_EMPTY(t->members)) {292decode_primitive ("bit_string", name, forwstr);293break;294}295fprintf(codefile,296"if (len < 1) return ASN1_OVERRUN;\n"297"p++; len--; ret++;\n");298fprintf(codefile,299"do {\n"300"if (len < 1) break;\n");301ASN1_TAILQ_FOREACH(m, t->members, members) {302while (m->val / 8 > pos / 8) {303fprintf (codefile,304"p++; len--; ret++;\n"305"if (len < 1) break;\n");306pos += 8;307}308fprintf (codefile,309"(%s)->%s = (*p >> %d) & 1;\n",310name, m->gen_name, 7 - m->val % 8);311}312fprintf(codefile,313"} while(0);\n");314fprintf (codefile,315"p += len; ret += len;\n");316break;317}318case TSequence: {319Member *m;320321if (t->members == NULL)322break;323324ASN1_TAILQ_FOREACH(m, t->members, members) {325char *s = NULL;326327if (m->ellipsis)328continue;329330if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&",331name, m->gen_name) < 0 || s == NULL)332errx(1, "malloc");333decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL,334depth + 1);335free (s);336}337338break;339}340case TSet: {341Member *m;342unsigned int memno;343344if(t->members == NULL)345break;346347fprintf(codefile, "{\n");348fprintf(codefile, "unsigned int members = 0;\n");349fprintf(codefile, "while(len > 0) {\n");350fprintf(codefile,351"Der_class class;\n"352"Der_type type;\n"353"int tag;\n"354"e = der_get_tag (p, len, &class, &type, &tag, NULL);\n"355"if(e) %s;\n", forwstr);356fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n");357memno = 0;358ASN1_TAILQ_FOREACH(m, t->members, members) {359char *s;360361assert(m->type->type == TTag);362363fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",364classname(m->type->tag.tagclass),365is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS",366valuename(m->type->tag.tagclass, m->type->tag.tagvalue));367368if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)369errx(1, "malloc");370if(m->optional)371fprintf(codefile,372"%s = calloc(1, sizeof(*%s));\n"373"if (%s == NULL) { e = ENOMEM; %s; }\n",374s, s, s, forwstr);375decode_type (s, m->type, 0, forwstr, m->gen_name, NULL, depth + 1);376free (s);377378fprintf(codefile, "members |= (1 << %d);\n", memno);379memno++;380fprintf(codefile, "break;\n");381}382fprintf(codefile,383"default:\n"384"return ASN1_MISPLACED_FIELD;\n"385"break;\n");386fprintf(codefile, "}\n");387fprintf(codefile, "}\n");388memno = 0;389ASN1_TAILQ_FOREACH(m, t->members, members) {390char *s;391392if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL)393errx(1, "malloc");394fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno);395if(m->optional)396fprintf(codefile, "%s = NULL;\n", s);397else if(m->defval)398gen_assign_defval(s, m->defval);399else400fprintf(codefile, "return ASN1_MISSING_FIELD;\n");401free(s);402memno++;403}404fprintf(codefile, "}\n");405break;406}407case TSetOf:408case TSequenceOf: {409char *n = NULL;410char *sname = NULL;411412fprintf (codefile,413"{\n"414"size_t %s_origlen = len;\n"415"size_t %s_oldret = ret;\n"416"size_t %s_olen = 0;\n"417"void *%s_tmp;\n"418"ret = 0;\n"419"(%s)->len = 0;\n"420"(%s)->val = NULL;\n",421tmpstr,422tmpstr,423tmpstr,424tmpstr,425name,426name);427428fprintf (codefile,429"while(ret < %s_origlen) {\n"430"size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n"431"if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n"432"%s_olen = %s_nlen;\n"433"%s_tmp = realloc((%s)->val, %s_olen);\n"434"if (%s_tmp == NULL) { e = ENOMEM; %s; }\n"435"(%s)->val = %s_tmp;\n",436tmpstr,437tmpstr, tmpstr, name,438tmpstr, tmpstr, forwstr,439tmpstr, tmpstr,440tmpstr, name, tmpstr,441tmpstr, forwstr,442name, tmpstr);443444if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL)445errx(1, "malloc");446if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL)447errx(1, "malloc");448decode_type (n, t->subtype, 0, forwstr, sname, NULL, depth + 1);449fprintf (codefile,450"(%s)->len++;\n"451"len = %s_origlen - ret;\n"452"}\n"453"ret += %s_oldret;\n"454"}\n",455name,456tmpstr, tmpstr);457if (t->range)458range_check(name, "len", forwstr, t->range);459free (n);460free (sname);461break;462}463case TGeneralizedTime:464decode_primitive ("generalized_time", name, forwstr);465break;466case TGeneralString:467decode_primitive ("general_string", name, forwstr);468break;469case TTeletexString:470decode_primitive ("general_string", name, forwstr);471break;472case TTag:{473char *tname = NULL, *typestring = NULL;474char *ide = NULL;475476if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL)477errx(1, "malloc");478479fprintf(codefile,480"{\n"481"size_t %s_datalen, %s_oldlen;\n"482"Der_type %s;\n",483tmpstr, tmpstr, typestring);484if(support_ber)485fprintf(codefile,486"int is_indefinite%u;\n", depth);487488fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "489"&%s_datalen, &l);\n",490classname(t->tag.tagclass),491typestring,492valuename(t->tag.tagclass, t->tag.tagvalue),493tmpstr);494495/* XXX hardcode for now */496if (support_ber && t->subtype->type == TOctetString) {497ide = typestring;498} else {499fprintf(codefile,500"if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n",501typestring,502is_primitive_type(t->subtype->type) ? "PRIM" : "CONS");503}504505if(optional) {506fprintf(codefile,507"if(e) {\n"508"%s = NULL;\n"509"} else {\n"510"%s = calloc(1, sizeof(*%s));\n"511"if (%s == NULL) { e = ENOMEM; %s; }\n",512name, name, name, name, forwstr);513} else {514fprintf(codefile, "if(e) %s;\n", forwstr);515}516fprintf (codefile,517"p += l; len -= l; ret += l;\n"518"%s_oldlen = len;\n",519tmpstr);520if(support_ber)521fprintf (codefile,522"if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n"523"{ e = ASN1_BAD_FORMAT; %s; }\n"524"if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",525depth, tmpstr, forwstr, depth, forwstr);526else527fprintf(codefile,528"if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"529"len = %s_datalen;\n", tmpstr, forwstr, tmpstr);530if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL)531errx(1, "malloc");532decode_type (name, t->subtype, 0, forwstr, tname, ide, depth + 1);533if(support_ber)534fprintf(codefile,535"if(is_indefinite%u){\n"536"len += 2;\n"537"e = der_match_tag_and_length(p, len, "538"(Der_class)0, &%s, UT_EndOfContent, "539"&%s_datalen, &l);\n"540"if(e) %s;\n"541"p += l; len -= l; ret += l;\n"542"if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n"543"} else \n",544depth,545typestring,546tmpstr,547forwstr,548typestring, forwstr);549fprintf(codefile,550"len = %s_oldlen - %s_datalen;\n",551tmpstr, tmpstr);552if(optional)553fprintf(codefile,554"}\n");555fprintf(codefile,556"}\n");557free(tname);558free(typestring);559break;560}561case TChoice: {562Member *m, *have_ellipsis = NULL;563const char *els = "";564565if (t->members == NULL)566break;567568ASN1_TAILQ_FOREACH(m, t->members, members) {569const Type *tt = m->type;570char *s = NULL;571Der_class cl;572Der_type ty;573unsigned tag;574575if (m->ellipsis) {576have_ellipsis = m;577continue;578}579580find_tag(tt, &cl, &ty, &tag);581582fprintf(codefile,583"%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n",584els,585classname(cl),586ty ? "CONS" : "PRIM",587valuename(cl, tag));588fprintf(codefile,589"(%s)->element = %s;\n",590name, m->label);591if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",592name, m->gen_name) < 0 || s == NULL)593errx(1, "malloc");594decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL,595depth + 1);596free(s);597fprintf(codefile,598"}\n");599els = "else ";600}601if (have_ellipsis) {602fprintf(codefile,603"else {\n"604"(%s)->element = %s;\n"605"(%s)->u.%s.data = calloc(1, len);\n"606"if ((%s)->u.%s.data == NULL) {\n"607"e = ENOMEM; %s;\n"608"}\n"609"(%s)->u.%s.length = len;\n"610"memcpy((%s)->u.%s.data, p, len);\n"611"p += len;\n"612"ret += len;\n"613"len = 0;\n"614"}\n",615name, have_ellipsis->label,616name, have_ellipsis->gen_name,617name, have_ellipsis->gen_name,618forwstr,619name, have_ellipsis->gen_name,620name, have_ellipsis->gen_name);621} else {622fprintf(codefile,623"else {\n"624"e = ASN1_PARSE_ERROR;\n"625"%s;\n"626"}\n",627forwstr);628}629break;630}631case TUTCTime:632decode_primitive ("utctime", name, forwstr);633break;634case TUTF8String:635decode_primitive ("utf8string", name, forwstr);636break;637case TPrintableString:638decode_primitive ("printable_string", name, forwstr);639break;640case TIA5String:641decode_primitive ("ia5_string", name, forwstr);642break;643case TBMPString:644decode_primitive ("bmp_string", name, forwstr);645break;646case TUniversalString:647decode_primitive ("universal_string", name, forwstr);648break;649case TVisibleString:650decode_primitive ("visible_string", name, forwstr);651break;652case TNull:653fprintf (codefile, "/* NULL */\n");654break;655case TOID:656decode_primitive ("oid", name, forwstr);657break;658default :659abort ();660}661return 0;662}663664void665generate_type_decode (const Symbol *s)666{667int preserve = preserve_type(s->name) ? TRUE : FALSE;668669fprintf (codefile, "int ASN1CALL\n"670"decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE,"671" size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n"672"{\n",673s->gen_name, s->gen_name);674675switch (s->type->type) {676case TInteger:677case TBoolean:678case TOctetString:679case TOID:680case TGeneralizedTime:681case TGeneralString:682case TTeletexString:683case TUTF8String:684case TPrintableString:685case TIA5String:686case TBMPString:687case TUniversalString:688case TVisibleString:689case TUTCTime:690case TNull:691case TEnumerated:692case TBitString:693case TSequence:694case TSequenceOf:695case TSet:696case TSetOf:697case TTag:698case TType:699case TChoice:700fprintf (codefile,701"size_t ret = 0;\n"702"size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"703"int e HEIMDAL_UNUSED_ATTRIBUTE;\n");704if (preserve)705fprintf (codefile, "const unsigned char *begin = p;\n");706707fprintf (codefile, "\n");708fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */709710decode_type ("data", s->type, 0, "goto fail", "Top", NULL, 1);711if (preserve)712fprintf (codefile,713"data->_save.data = calloc(1, ret);\n"714"if (data->_save.data == NULL) { \n"715"e = ENOMEM; goto fail; \n"716"}\n"717"data->_save.length = ret;\n"718"memcpy(data->_save.data, begin, ret);\n");719fprintf (codefile,720"if(size) *size = ret;\n"721"return 0;\n");722fprintf (codefile,723"fail:\n"724"free_%s(data);\n"725"return e;\n",726s->gen_name);727break;728default:729abort ();730}731fprintf (codefile, "}\n\n");732}733734735