1 /* tasn_enc.c */ 2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL 3 * project 2000. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 60 #include <stddef.h> 61 #include <string.h> 62 #include <openssl/asn1.h> 63 #include <openssl/asn1t.h> 64 #include <openssl/objects.h> 65 66 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); 67 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *seq, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int isset); 68 69 /* Encode an ASN1 item, this is compatible with the 70 * standard 'i2d' function. 'out' points to 71 * a buffer to output the data to, in future we will 72 * have more advanced versions that can output data 73 * a piece at a time and this will simply be a special 74 * case. 75 * 76 * The new i2d has one additional feature. If the output 77 * buffer is NULL (i.e. *out == NULL) then a buffer is 78 * allocated and populated with the encoding. 79 */ 80 81 82 int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) 83 { 84 if(out && !*out) { 85 unsigned char *p, *buf; 86 int len; 87 len = ASN1_item_ex_i2d(&val, NULL, it, -1, 0); 88 if(len <= 0) return len; 89 buf = OPENSSL_malloc(len); 90 if(!buf) return -1; 91 p = buf; 92 ASN1_item_ex_i2d(&val, &p, it, -1, 0); 93 *out = buf; 94 return len; 95 } 96 97 return ASN1_item_ex_i2d(&val, out, it, -1, 0); 98 } 99 100 /* Encode an item, taking care of IMPLICIT tagging (if any). 101 * This function performs the normal item handling: it can be 102 * used in external types. 103 */ 104 105 int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) 106 { 107 const ASN1_TEMPLATE *tt = NULL; 108 unsigned char *p = NULL; 109 int i, seqcontlen, seqlen; 110 ASN1_STRING *strtmp; 111 const ASN1_COMPAT_FUNCS *cf; 112 const ASN1_EXTERN_FUNCS *ef; 113 const ASN1_AUX *aux = it->funcs; 114 ASN1_aux_cb *asn1_cb; 115 if((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) return 0; 116 if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb; 117 else asn1_cb = 0; 118 119 switch(it->itype) { 120 121 case ASN1_ITYPE_PRIMITIVE: 122 if(it->templates) 123 return ASN1_template_i2d(pval, out, it->templates); 124 return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); 125 break; 126 127 case ASN1_ITYPE_MSTRING: 128 strtmp = (ASN1_STRING *)*pval; 129 return asn1_i2d_ex_primitive(pval, out, it, -1, 0); 130 131 case ASN1_ITYPE_CHOICE: 132 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) 133 return 0; 134 i = asn1_get_choice_selector(pval, it); 135 if((i >= 0) && (i < it->tcount)) { 136 ASN1_VALUE **pchval; 137 const ASN1_TEMPLATE *chtt; 138 chtt = it->templates + i; 139 pchval = asn1_get_field_ptr(pval, chtt); 140 return ASN1_template_i2d(pchval, out, chtt); 141 } 142 /* Fixme: error condition if selector out of range */ 143 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) 144 return 0; 145 break; 146 147 case ASN1_ITYPE_EXTERN: 148 /* If new style i2d it does all the work */ 149 ef = it->funcs; 150 return ef->asn1_ex_i2d(pval, out, it, tag, aclass); 151 152 case ASN1_ITYPE_COMPAT: 153 /* old style hackery... */ 154 cf = it->funcs; 155 if(out) p = *out; 156 i = cf->asn1_i2d(*pval, out); 157 /* Fixup for IMPLICIT tag: note this messes up for tags > 30, 158 * but so did the old code. Tags > 30 are very rare anyway. 159 */ 160 if(out && (tag != -1)) 161 *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); 162 return i; 163 164 case ASN1_ITYPE_SEQUENCE: 165 i = asn1_enc_restore(&seqcontlen, out, pval, it); 166 /* An error occurred */ 167 if(i < 0) return 0; 168 /* We have a valid cached encoding... */ 169 if(i > 0) return seqcontlen; 170 /* Otherwise carry on */ 171 seqcontlen = 0; 172 /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ 173 if(tag == -1) { 174 tag = V_ASN1_SEQUENCE; 175 aclass = V_ASN1_UNIVERSAL; 176 } 177 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it)) 178 return 0; 179 /* First work out sequence content length */ 180 for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 181 const ASN1_TEMPLATE *seqtt; 182 ASN1_VALUE **pseqval; 183 seqtt = asn1_do_adb(pval, tt, 1); 184 if(!seqtt) return 0; 185 pseqval = asn1_get_field_ptr(pval, seqtt); 186 /* FIXME: check for errors in enhanced version */ 187 /* FIXME: special handling of indefinite length encoding */ 188 seqcontlen += ASN1_template_i2d(pseqval, NULL, seqtt); 189 } 190 seqlen = ASN1_object_size(1, seqcontlen, tag); 191 if(!out) return seqlen; 192 /* Output SEQUENCE header */ 193 ASN1_put_object(out, 1, seqcontlen, tag, aclass); 194 for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 195 const ASN1_TEMPLATE *seqtt; 196 ASN1_VALUE **pseqval; 197 seqtt = asn1_do_adb(pval, tt, 1); 198 if(!seqtt) return 0; 199 pseqval = asn1_get_field_ptr(pval, seqtt); 200 /* FIXME: check for errors in enhanced version */ 201 ASN1_template_i2d(pseqval, out, seqtt); 202 } 203 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it)) 204 return 0; 205 return seqlen; 206 207 default: 208 return 0; 209 } 210 return 0; 211 } 212 213 int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt) 214 { 215 int i, ret, flags, aclass; 216 flags = tt->flags; 217 aclass = flags & ASN1_TFLG_TAG_CLASS; 218 if(flags & ASN1_TFLG_SK_MASK) { 219 /* SET OF, SEQUENCE OF */ 220 STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; 221 int isset, sktag, skaclass; 222 int skcontlen, sklen; 223 ASN1_VALUE *skitem; 224 if(!*pval) return 0; 225 if(flags & ASN1_TFLG_SET_OF) { 226 isset = 1; 227 /* 2 means we reorder */ 228 if(flags & ASN1_TFLG_SEQUENCE_OF) isset = 2; 229 } else isset = 0; 230 /* First work out inner tag value */ 231 if(flags & ASN1_TFLG_IMPTAG) { 232 sktag = tt->tag; 233 skaclass = aclass; 234 } else { 235 skaclass = V_ASN1_UNIVERSAL; 236 if(isset) sktag = V_ASN1_SET; 237 else sktag = V_ASN1_SEQUENCE; 238 } 239 /* Now work out length of items */ 240 skcontlen = 0; 241 for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 242 skitem = sk_ASN1_VALUE_value(sk, i); 243 skcontlen += ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), -1, 0); 244 } 245 sklen = ASN1_object_size(1, skcontlen, sktag); 246 /* If EXPLICIT need length of surrounding tag */ 247 if(flags & ASN1_TFLG_EXPTAG) 248 ret = ASN1_object_size(1, sklen, tt->tag); 249 else ret = sklen; 250 251 if(!out) return ret; 252 253 /* Now encode this lot... */ 254 /* EXPLICIT tag */ 255 if(flags & ASN1_TFLG_EXPTAG) 256 ASN1_put_object(out, 1, sklen, tt->tag, aclass); 257 /* SET or SEQUENCE and IMPLICIT tag */ 258 ASN1_put_object(out, 1, skcontlen, sktag, skaclass); 259 /* And finally the stuff itself */ 260 asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), isset); 261 262 return ret; 263 } 264 265 if(flags & ASN1_TFLG_EXPTAG) { 266 /* EXPLICIT tagging */ 267 /* Find length of tagged item */ 268 i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, 0); 269 if(!i) return 0; 270 /* Find length of EXPLICIT tag */ 271 ret = ASN1_object_size(1, i, tt->tag); 272 if(out) { 273 /* Output tag and item */ 274 ASN1_put_object(out, 1, i, tt->tag, aclass); 275 ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0); 276 } 277 return ret; 278 } 279 if(flags & ASN1_TFLG_IMPTAG) { 280 /* IMPLICIT tagging */ 281 return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), tt->tag, aclass); 282 } 283 /* Nothing special: treat as normal */ 284 return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0); 285 } 286 287 /* Temporary structure used to hold DER encoding of items for SET OF */ 288 289 typedef struct { 290 unsigned char *data; 291 int length; 292 ASN1_VALUE *field; 293 } DER_ENC; 294 295 static int der_cmp(const void *a, const void *b) 296 { 297 const DER_ENC *d1 = a, *d2 = b; 298 int cmplen, i; 299 cmplen = (d1->length < d2->length) ? d1->length : d2->length; 300 i = memcmp(d1->data, d2->data, cmplen); 301 if(i) return i; 302 return d1->length - d2->length; 303 } 304 305 /* Output the content octets of SET OF or SEQUENCE OF */ 306 307 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int do_sort) 308 { 309 int i; 310 ASN1_VALUE *skitem; 311 unsigned char *tmpdat = NULL, *p = NULL; 312 DER_ENC *derlst = NULL, *tder; 313 if(do_sort) { 314 /* Don't need to sort less than 2 items */ 315 if(sk_ASN1_VALUE_num(sk) < 2) do_sort = 0; 316 else { 317 derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) * sizeof(*derlst)); 318 tmpdat = OPENSSL_malloc(skcontlen); 319 if(!derlst || !tmpdat) return 0; 320 } 321 } 322 /* If not sorting just output each item */ 323 if(!do_sort) { 324 for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 325 skitem = sk_ASN1_VALUE_value(sk, i); 326 ASN1_item_i2d(skitem, out, item); 327 } 328 return 1; 329 } 330 p = tmpdat; 331 /* Doing sort: build up a list of each member's DER encoding */ 332 for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 333 skitem = sk_ASN1_VALUE_value(sk, i); 334 tder->data = p; 335 tder->length = ASN1_item_i2d(skitem, &p, item); 336 tder->field = skitem; 337 } 338 /* Now sort them */ 339 qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); 340 /* Output sorted DER encoding */ 341 p = *out; 342 for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 343 memcpy(p, tder->data, tder->length); 344 p += tder->length; 345 } 346 *out = p; 347 /* If do_sort is 2 then reorder the STACK */ 348 if(do_sort == 2) { 349 for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) 350 sk_ASN1_VALUE_set(sk, i, tder->field); 351 } 352 OPENSSL_free(derlst); 353 OPENSSL_free(tmpdat); 354 return 1; 355 } 356 357 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) 358 { 359 int len; 360 int utype; 361 int usetag; 362 363 utype = it->utype; 364 365 /* Get length of content octets and maybe find 366 * out the underlying type. 367 */ 368 369 len = asn1_ex_i2c(pval, NULL, &utype, it); 370 371 /* If SEQUENCE, SET or OTHER then header is 372 * included in pseudo content octets so don't 373 * include tag+length. We need to check here 374 * because the call to asn1_ex_i2c() could change 375 * utype. 376 */ 377 if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || 378 (utype == V_ASN1_OTHER)) 379 usetag = 0; 380 else usetag = 1; 381 382 /* -1 means omit type */ 383 384 if(len == -1) return 0; 385 386 /* If not implicitly tagged get tag from underlying type */ 387 if(tag == -1) tag = utype; 388 389 /* Output tag+length followed by content octets */ 390 if(out) { 391 if(usetag) ASN1_put_object(out, 0, len, tag, aclass); 392 asn1_ex_i2c(pval, *out, &utype, it); 393 *out += len; 394 } 395 396 if(usetag) return ASN1_object_size(0, len, tag); 397 return len; 398 } 399 400 /* Produce content octets from a structure */ 401 402 int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ITEM *it) 403 { 404 ASN1_BOOLEAN *tbool = NULL; 405 ASN1_STRING *strtmp; 406 ASN1_OBJECT *otmp; 407 int utype; 408 unsigned char *cont, c; 409 int len; 410 const ASN1_PRIMITIVE_FUNCS *pf; 411 pf = it->funcs; 412 if(pf && pf->prim_i2c) return pf->prim_i2c(pval, cout, putype, it); 413 414 /* Should type be omitted? */ 415 if((it->itype != ASN1_ITYPE_PRIMITIVE) || (it->utype != V_ASN1_BOOLEAN)) { 416 if(!*pval) return -1; 417 } 418 419 if(it->itype == ASN1_ITYPE_MSTRING) { 420 /* If MSTRING type set the underlying type */ 421 strtmp = (ASN1_STRING *)*pval; 422 utype = strtmp->type; 423 *putype = utype; 424 } else if(it->utype == V_ASN1_ANY) { 425 /* If ANY set type and pointer to value */ 426 ASN1_TYPE *typ; 427 typ = (ASN1_TYPE *)*pval; 428 utype = typ->type; 429 *putype = utype; 430 pval = (ASN1_VALUE **)&typ->value.ptr; 431 } else utype = *putype; 432 433 switch(utype) { 434 case V_ASN1_OBJECT: 435 otmp = (ASN1_OBJECT *)*pval; 436 cont = otmp->data; 437 len = otmp->length; 438 break; 439 440 case V_ASN1_NULL: 441 cont = NULL; 442 len = 0; 443 break; 444 445 case V_ASN1_BOOLEAN: 446 tbool = (ASN1_BOOLEAN *)pval; 447 if(*tbool == -1) return -1; 448 /* Default handling if value == size field then omit */ 449 if(*tbool && (it->size > 0)) return -1; 450 if(!*tbool && !it->size) return -1; 451 c = (unsigned char)*tbool; 452 cont = &c; 453 len = 1; 454 break; 455 456 case V_ASN1_BIT_STRING: 457 return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, cout ? &cout : NULL); 458 break; 459 460 case V_ASN1_INTEGER: 461 case V_ASN1_NEG_INTEGER: 462 case V_ASN1_ENUMERATED: 463 case V_ASN1_NEG_ENUMERATED: 464 /* These are all have the same content format 465 * as ASN1_INTEGER 466 */ 467 return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); 468 break; 469 470 case V_ASN1_OCTET_STRING: 471 case V_ASN1_NUMERICSTRING: 472 case V_ASN1_PRINTABLESTRING: 473 case V_ASN1_T61STRING: 474 case V_ASN1_VIDEOTEXSTRING: 475 case V_ASN1_IA5STRING: 476 case V_ASN1_UTCTIME: 477 case V_ASN1_GENERALIZEDTIME: 478 case V_ASN1_GRAPHICSTRING: 479 case V_ASN1_VISIBLESTRING: 480 case V_ASN1_GENERALSTRING: 481 case V_ASN1_UNIVERSALSTRING: 482 case V_ASN1_BMPSTRING: 483 case V_ASN1_UTF8STRING: 484 case V_ASN1_SEQUENCE: 485 case V_ASN1_SET: 486 default: 487 /* All based on ASN1_STRING and handled the same */ 488 strtmp = (ASN1_STRING *)*pval; 489 cont = strtmp->data; 490 len = strtmp->length; 491 492 break; 493 494 } 495 if(cout && len) memcpy(cout, cont, len); 496 return len; 497 } 498