1 /* 2 * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "gen_locl.h" 35 36 RCSID("$Id: gen_encode.c,v 1.12 2001/09/25 13:39:26 assar Exp $"); 37 38 static void 39 encode_primitive (const char *typename, const char *name) 40 { 41 fprintf (codefile, 42 "e = encode_%s(p, len, %s, &l);\n" 43 "BACK;\n", 44 typename, 45 name); 46 } 47 48 static void 49 encode_type (const char *name, const Type *t) 50 { 51 switch (t->type) { 52 case TType: 53 #if 0 54 encode_type (name, t->symbol->type); 55 #endif 56 fprintf (codefile, 57 "e = encode_%s(p, len, %s, &l);\n" 58 "BACK;\n", 59 t->symbol->gen_name, name); 60 break; 61 case TInteger: 62 if(t->members == NULL) 63 encode_primitive ("integer", name); 64 else { 65 char *s; 66 asprintf(&s, "(const int*)%s", name); 67 if(s == NULL) 68 errx(1, "out of memory"); 69 encode_primitive ("integer", s); 70 free(s); 71 } 72 break; 73 case TUInteger: 74 encode_primitive ("unsigned", name); 75 break; 76 case TOctetString: 77 encode_primitive ("octet_string", name); 78 break; 79 case TOID : 80 encode_primitive ("oid", name); 81 break; 82 case TBitString: { 83 Member *m; 84 int pos; 85 int rest; 86 int tag = -1; 87 88 if (t->members == NULL) 89 break; 90 91 fprintf (codefile, "{\n" 92 "unsigned char c = 0;\n"); 93 pos = t->members->prev->val; 94 /* fix for buggy MIT (and OSF?) code */ 95 if (pos > 31) 96 abort (); 97 /* 98 * It seems that if we do not always set pos to 31 here, the MIT 99 * code will do the wrong thing. 100 * 101 * I hate ASN.1 (and DER), but I hate it even more when everybody 102 * has to screw it up differently. 103 */ 104 pos = 31; 105 rest = 7 - (pos % 8); 106 107 for (m = t->members->prev; m && tag != m->val; m = m->prev) { 108 while (m->val / 8 < pos / 8) { 109 fprintf (codefile, 110 "*p-- = c; len--; ret++;\n" 111 "c = 0;\n"); 112 pos -= 8; 113 } 114 fprintf (codefile, 115 "if(%s->%s) c |= 1<<%d;\n", name, m->gen_name, 116 7 - m->val % 8); 117 118 if (tag == -1) 119 tag = m->val; 120 } 121 122 fprintf (codefile, 123 "*p-- = c;\n" 124 "*p-- = %d;\n" 125 "len -= 2;\n" 126 "ret += 2;\n" 127 "}\n\n" 128 "e = der_put_length_and_tag (p, len, ret, UNIV, PRIM," 129 "UT_BitString, &l);\n" 130 "BACK;\n", 131 rest); 132 break; 133 } 134 case TEnumerated : { 135 encode_primitive ("enumerated", name); 136 break; 137 } 138 case TSequence: { 139 Member *m; 140 int tag = -1; 141 142 if (t->members == NULL) 143 break; 144 145 for (m = t->members->prev; m && tag != m->val; m = m->prev) { 146 char *s; 147 148 asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name); 149 if (m->optional) 150 fprintf (codefile, 151 "if(%s)\n", 152 s); 153 #if 1 154 fprintf (codefile, "{\n" 155 "int oldret = ret;\n" 156 "ret = 0;\n"); 157 #endif 158 encode_type (s, m->type); 159 fprintf (codefile, 160 "e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, " 161 "%d, &l);\n" 162 "BACK;\n", 163 m->val); 164 #if 1 165 fprintf (codefile, 166 "ret += oldret;\n" 167 "}\n"); 168 #endif 169 if (tag == -1) 170 tag = m->val; 171 free (s); 172 } 173 fprintf (codefile, 174 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n" 175 "BACK;\n"); 176 break; 177 } 178 case TSequenceOf: { 179 char *n; 180 181 fprintf (codefile, 182 "for(i = (%s)->len - 1; i >= 0; --i) {\n" 183 #if 1 184 "int oldret = ret;\n" 185 "ret = 0;\n", 186 #else 187 , 188 #endif 189 name); 190 asprintf (&n, "&(%s)->val[i]", name); 191 encode_type (n, t->subtype); 192 fprintf (codefile, 193 #if 1 194 "ret += oldret;\n" 195 #endif 196 "}\n" 197 "e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l);\n" 198 "BACK;\n"); 199 free (n); 200 break; 201 } 202 case TGeneralizedTime: 203 encode_primitive ("generalized_time", name); 204 break; 205 case TGeneralString: 206 encode_primitive ("general_string", name); 207 break; 208 case TApplication: 209 encode_type (name, t->subtype); 210 fprintf (codefile, 211 "e = der_put_length_and_tag (p, len, ret, APPL, CONS, %d, &l);\n" 212 "BACK;\n", 213 t->application); 214 break; 215 default: 216 abort (); 217 } 218 } 219 220 void 221 generate_type_encode (const Symbol *s) 222 { 223 fprintf (headerfile, 224 "int " 225 "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", 226 s->gen_name, s->gen_name); 227 228 fprintf (codefile, "#define BACK if (e) return e; p -= l; len -= l; ret += l\n\n"); 229 230 231 fprintf (codefile, "int\n" 232 "encode_%s(unsigned char *p, size_t len," 233 " const %s *data, size_t *size)\n" 234 "{\n", 235 s->gen_name, s->gen_name); 236 237 switch (s->type->type) { 238 case TInteger: 239 case TUInteger: 240 case TOctetString: 241 case TGeneralizedTime: 242 case TGeneralString: 243 case TBitString: 244 case TEnumerated: 245 case TOID: 246 case TSequence: 247 case TSequenceOf: 248 case TApplication: 249 case TType: 250 fprintf (codefile, 251 "size_t ret = 0;\n" 252 "size_t l;\n" 253 "int i, e;\n\n"); 254 fprintf(codefile, "i = 0;\n"); /* hack to avoid `unused variable' */ 255 256 encode_type("data", s->type); 257 258 fprintf (codefile, "*size = ret;\n" 259 "return 0;\n"); 260 break; 261 default: 262 abort (); 263 } 264 fprintf (codefile, "}\n\n"); 265 } 266