Path: blob/main/crypto/heimdal/lib/asn1/gen_encode.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"3435RCSID("$Id$");3637static void38encode_primitive (const char *typename, const char *name)39{40fprintf (codefile,41"e = der_put_%s(p, len, %s, &l);\n"42"if (e) return e;\np -= l; len -= l; ret += l;\n\n",43typename,44name);45}4647const char *48classname(Der_class class)49{50const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",51"ASN1_C_CONTEXT", "ASN1_C_PRIV" };52if(class < ASN1_C_UNIV || class > ASN1_C_PRIVATE)53return "???";54return cn[class];55}565758const char *59valuename(Der_class class, int value)60{61static char s[32];62struct {63int value;64const char *s;65} *p, values[] = {66#define X(Y) { Y, #Y }67X(UT_BMPString),68X(UT_BitString),69X(UT_Boolean),70X(UT_EmbeddedPDV),71X(UT_Enumerated),72X(UT_External),73X(UT_GeneralString),74X(UT_GeneralizedTime),75X(UT_GraphicString),76X(UT_IA5String),77X(UT_Integer),78X(UT_Null),79X(UT_NumericString),80X(UT_OID),81X(UT_ObjectDescriptor),82X(UT_OctetString),83X(UT_PrintableString),84X(UT_Real),85X(UT_RelativeOID),86X(UT_Sequence),87X(UT_Set),88X(UT_TeletexString),89X(UT_UTCTime),90X(UT_UTF8String),91X(UT_UniversalString),92X(UT_VideotexString),93X(UT_VisibleString),94#undef X95{ -1, NULL }96};97if(class == ASN1_C_UNIV) {98for(p = values; p->value != -1; p++)99if(p->value == value)100return p->s;101}102snprintf(s, sizeof(s), "%d", value);103return s;104}105106static int107encode_type (const char *name, const Type *t, const char *tmpstr)108{109int constructed = 1;110111switch (t->type) {112case TType:113#if 0114encode_type (name, t->symbol->type);115#endif116fprintf (codefile,117"e = encode_%s(p, len, %s, &l);\n"118"if (e) return e;\np -= l; len -= l; ret += l;\n\n",119t->symbol->gen_name, name);120break;121case TInteger:122if(t->members) {123fprintf(codefile,124"{\n"125"int enumint = (int)*%s;\n",126name);127encode_primitive ("integer", "&enumint");128fprintf(codefile, "}\n;");129} else if (t->range == NULL) {130encode_primitive ("heim_integer", name);131} else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) {132encode_primitive ("integer64", name);133} else if (t->range->min >= 0 && t->range->max > UINT_MAX) {134encode_primitive ("unsigned64", name);135} else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) {136encode_primitive ("integer", name);137} else if (t->range->min >= 0 && t->range->max <= UINT_MAX) {138encode_primitive ("unsigned", name);139} else140errx(1, "%s: unsupported range %" PRId64 " -> %" PRId64,141name, t->range->min, t->range->max);142constructed = 0;143break;144case TBoolean:145encode_primitive ("boolean", name);146constructed = 0;147break;148case TOctetString:149encode_primitive ("octet_string", name);150constructed = 0;151break;152case TBitString: {153Member *m;154int pos;155156if (ASN1_TAILQ_EMPTY(t->members)) {157encode_primitive("bit_string", name);158constructed = 0;159break;160}161162fprintf (codefile, "{\n"163"unsigned char c = 0;\n");164if (!rfc1510_bitstring)165fprintf (codefile,166"int rest = 0;\n"167"int bit_set = 0;\n");168#if 0169pos = t->members->prev->val;170/* fix for buggy MIT (and OSF?) code */171if (pos > 31)172abort ();173#endif174/*175* It seems that if we do not always set pos to 31 here, the MIT176* code will do the wrong thing.177*178* I hate ASN.1 (and DER), but I hate it even more when everybody179* has to screw it up differently.180*/181pos = ASN1_TAILQ_LAST(t->members, memhead)->val;182if (rfc1510_bitstring) {183if (pos < 31)184pos = 31;185}186187ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {188while (m->val / 8 < pos / 8) {189if (!rfc1510_bitstring)190fprintf (codefile,191"if (c != 0 || bit_set) {\n");192fprintf (codefile,193"if (len < 1) return ASN1_OVERFLOW;\n"194"*p-- = c; len--; ret++;\n");195if (!rfc1510_bitstring)196fprintf (codefile,197"if (!bit_set) {\n"198"rest = 0;\n"199"while(c) { \n"200"if (c & 1) break;\n"201"c = c >> 1;\n"202"rest++;\n"203"}\n"204"bit_set = 1;\n"205"}\n"206"}\n");207fprintf (codefile,208"c = 0;\n");209pos -= 8;210}211fprintf (codefile,212"if((%s)->%s) {\n"213"c |= 1<<%d;\n",214name, m->gen_name, 7 - m->val % 8);215fprintf (codefile,216"}\n");217}218219if (!rfc1510_bitstring)220fprintf (codefile,221"if (c != 0 || bit_set) {\n");222fprintf (codefile,223"if (len < 1) return ASN1_OVERFLOW;\n"224"*p-- = c; len--; ret++;\n");225if (!rfc1510_bitstring)226fprintf (codefile,227"if (!bit_set) {\n"228"rest = 0;\n"229"if(c) { \n"230"while(c) { \n"231"if (c & 1) break;\n"232"c = c >> 1;\n"233"rest++;\n"234"}\n"235"}\n"236"}\n"237"}\n");238239fprintf (codefile,240"if (len < 1) return ASN1_OVERFLOW;\n"241"*p-- = %s;\n"242"len -= 1;\n"243"ret += 1;\n"244"}\n\n",245rfc1510_bitstring ? "0" : "rest");246constructed = 0;247break;248}249case TEnumerated : {250encode_primitive ("enumerated", name);251constructed = 0;252break;253}254255case TSet:256case TSequence: {257Member *m;258259if (t->members == NULL)260break;261262ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {263char *s = NULL;264265if (m->ellipsis)266continue;267268if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)269errx(1, "malloc");270fprintf(codefile, "/* %s */\n", m->name);271if (m->optional)272fprintf (codefile,273"if(%s) ",274s);275else if(m->defval)276gen_compare_defval(s + 1, m->defval);277fprintf (codefile, "{\n");278fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr);279fprintf (codefile, "ret = 0;\n");280encode_type (s, m->type, m->gen_name);281fprintf (codefile, "ret += %s_oldret;\n", tmpstr);282fprintf (codefile, "}\n");283free (s);284}285break;286}287case TSetOf: {288289fprintf(codefile,290"{\n"291"struct heim_octet_string *val;\n"292"size_t elen = 0, totallen = 0;\n"293"int eret = 0;\n");294295fprintf(codefile,296"if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"297"return ERANGE;\n",298name);299300fprintf(codefile,301"val = malloc(sizeof(val[0]) * (%s)->len);\n"302"if (val == NULL && (%s)->len != 0) return ENOMEM;\n",303name, name);304305fprintf(codefile,306"for(i = 0; i < (int)(%s)->len; i++) {\n",307name);308309fprintf(codefile,310"ASN1_MALLOC_ENCODE(%s, val[i].data, "311"val[i].length, &(%s)->val[i], &elen, eret);\n",312t->subtype->symbol->gen_name,313name);314315fprintf(codefile,316"if(eret) {\n"317"i--;\n"318"while (i >= 0) {\n"319"free(val[i].data);\n"320"i--;\n"321"}\n"322"free(val);\n"323"return eret;\n"324"}\n"325"totallen += elen;\n"326"}\n");327328fprintf(codefile,329"if (totallen > len) {\n"330"for (i = 0; i < (int)(%s)->len; i++) {\n"331"free(val[i].data);\n"332"}\n"333"free(val);\n"334"return ASN1_OVERFLOW;\n"335"}\n",336name);337338fprintf(codefile,339"qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",340name);341342fprintf (codefile,343"for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"344"p -= val[i].length;\n"345"ret += val[i].length;\n"346"memcpy(p + 1, val[i].data, val[i].length);\n"347"free(val[i].data);\n"348"}\n"349"free(val);\n"350"}\n",351name);352break;353}354case TSequenceOf: {355char *sname = NULL;356char *n = NULL;357358fprintf (codefile,359"for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"360"size_t %s_for_oldret = ret;\n"361"ret = 0;\n",362name, tmpstr);363if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL)364errx(1, "malloc");365if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)366errx(1, "malloc");367encode_type (n, t->subtype, sname);368fprintf (codefile,369"ret += %s_for_oldret;\n"370"}\n",371tmpstr);372free (n);373free (sname);374break;375}376case TGeneralizedTime:377encode_primitive ("generalized_time", name);378constructed = 0;379break;380case TGeneralString:381encode_primitive ("general_string", name);382constructed = 0;383break;384case TTeletexString:385encode_primitive ("general_string", name);386constructed = 0;387break;388case TTag: {389char *tname = NULL;390int c;391if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)392errx(1, "malloc");393c = encode_type (name, t->subtype, tname);394fprintf (codefile,395"e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"396"if (e) return e;\np -= l; len -= l; ret += l;\n\n",397classname(t->tag.tagclass),398c ? "CONS" : "PRIM",399valuename(t->tag.tagclass, t->tag.tagvalue));400free (tname);401break;402}403case TChoice:{404Member *m, *have_ellipsis = NULL;405char *s = NULL;406407if (t->members == NULL)408break;409410fprintf(codefile, "\n");411412if (asprintf (&s, "(%s)", name) < 0 || s == NULL)413errx(1, "malloc");414fprintf(codefile, "switch(%s->element) {\n", s);415416ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {417char *s2 = NULL;418419if (m->ellipsis) {420have_ellipsis = m;421continue;422}423424fprintf (codefile, "case %s: {", m->label);425if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",426s, m->gen_name) < 0 || s2 == NULL)427errx(1, "malloc");428if (m->optional)429fprintf (codefile, "if(%s) {\n", s2);430fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);431fprintf (codefile, "ret = 0;\n");432constructed = encode_type (s2, m->type, m->gen_name);433fprintf (codefile, "ret += %s_oldret;\n", tmpstr);434if(m->optional)435fprintf (codefile, "}\n");436fprintf(codefile, "break;\n");437fprintf(codefile, "}\n");438free (s2);439}440free (s);441if (have_ellipsis) {442fprintf(codefile,443"case %s: {\n"444"if (len < (%s)->u.%s.length)\n"445"return ASN1_OVERFLOW;\n"446"p -= (%s)->u.%s.length;\n"447"ret += (%s)->u.%s.length;\n"448"memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"449"break;\n"450"}\n",451have_ellipsis->label,452name, have_ellipsis->gen_name,453name, have_ellipsis->gen_name,454name, have_ellipsis->gen_name,455name, have_ellipsis->gen_name,456name, have_ellipsis->gen_name);457}458fprintf(codefile, "};\n");459break;460}461case TOID:462encode_primitive ("oid", name);463constructed = 0;464break;465case TUTCTime:466encode_primitive ("utctime", name);467constructed = 0;468break;469case TUTF8String:470encode_primitive ("utf8string", name);471constructed = 0;472break;473case TPrintableString:474encode_primitive ("printable_string", name);475constructed = 0;476break;477case TIA5String:478encode_primitive ("ia5_string", name);479constructed = 0;480break;481case TBMPString:482encode_primitive ("bmp_string", name);483constructed = 0;484break;485case TUniversalString:486encode_primitive ("universal_string", name);487constructed = 0;488break;489case TVisibleString:490encode_primitive ("visible_string", name);491constructed = 0;492break;493case TNull:494fprintf (codefile, "/* NULL */\n");495constructed = 0;496break;497default:498abort ();499}500return constructed;501}502503void504generate_type_encode (const Symbol *s)505{506fprintf (codefile, "int ASN1CALL\n"507"encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE,"508" const %s *data, size_t *size)\n"509"{\n",510s->gen_name, s->gen_name);511512switch (s->type->type) {513case TInteger:514case TBoolean:515case TOctetString:516case TGeneralizedTime:517case TGeneralString:518case TTeletexString:519case TUTCTime:520case TUTF8String:521case TPrintableString:522case TIA5String:523case TBMPString:524case TUniversalString:525case TVisibleString:526case TNull:527case TBitString:528case TEnumerated:529case TOID:530case TSequence:531case TSequenceOf:532case TSet:533case TSetOf:534case TTag:535case TType:536case TChoice:537fprintf (codefile,538"size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n"539"size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"540"int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n");541542encode_type("data", s->type, "Top");543544fprintf (codefile, "*size = ret;\n"545"return 0;\n");546break;547default:548abort ();549}550fprintf (codefile, "}\n\n");551}552553554