1 /* $OpenBSD: tasn_enc.c,v 1.22 2019/04/01 15:48:04 jsing Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2000. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2000-2004 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 #include <stddef.h> 60 #include <string.h> 61 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, 67 const ASN1_ITEM *it, int tag, int aclass); 68 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, 69 int skcontlen, const ASN1_ITEM *item, int do_sort, int iclass); 70 static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 71 const ASN1_TEMPLATE *tt, int tag, int aclass); 72 static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, 73 const ASN1_ITEM *it, int flags); 74 static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, 75 const ASN1_ITEM *it); 76 77 /* Top level i2d equivalents: the 'ndef' variant instructs the encoder 78 * to use indefinite length constructed encoding, where appropriate 79 */ 80 81 int 82 ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) 83 { 84 return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); 85 } 86 87 int 88 ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) 89 { 90 return asn1_item_flags_i2d(val, out, it, 0); 91 } 92 93 /* Encode an ASN1 item, this is use by the 94 * standard 'i2d' function. 'out' points to 95 * a buffer to output the data to. 96 * 97 * The new i2d has one additional feature. If the output 98 * buffer is NULL (i.e. *out == NULL) then a buffer is 99 * allocated and populated with the encoding. 100 */ 101 102 static int 103 asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it, 104 int flags) 105 { 106 if (out && !*out) { 107 unsigned char *p, *buf; 108 int len; 109 len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); 110 if (len <= 0) 111 return len; 112 buf = malloc(len); 113 if (!buf) 114 return -1; 115 p = buf; 116 ASN1_item_ex_i2d(&val, &p, it, -1, flags); 117 *out = buf; 118 return len; 119 } 120 121 return ASN1_item_ex_i2d(&val, out, it, -1, flags); 122 } 123 124 /* Encode an item, taking care of IMPLICIT tagging (if any). 125 * This function performs the normal item handling: it can be 126 * used in external types. 127 */ 128 129 int 130 ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, 131 int tag, int aclass) 132 { 133 const ASN1_TEMPLATE *tt = NULL; 134 int i, seqcontlen, seqlen, ndef = 1; 135 const ASN1_EXTERN_FUNCS *ef; 136 const ASN1_AUX *aux = it->funcs; 137 ASN1_aux_cb *asn1_cb = NULL; 138 139 if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) 140 return 0; 141 142 if (aux && aux->asn1_cb) 143 asn1_cb = aux->asn1_cb; 144 145 switch (it->itype) { 146 147 case ASN1_ITYPE_PRIMITIVE: 148 if (it->templates) 149 return asn1_template_ex_i2d(pval, out, it->templates, 150 tag, aclass); 151 return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); 152 break; 153 154 case ASN1_ITYPE_MSTRING: 155 return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); 156 157 case ASN1_ITYPE_CHOICE: 158 if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 159 return 0; 160 i = asn1_get_choice_selector(pval, it); 161 if ((i >= 0) && (i < it->tcount)) { 162 ASN1_VALUE **pchval; 163 const ASN1_TEMPLATE *chtt; 164 chtt = it->templates + i; 165 pchval = asn1_get_field_ptr(pval, chtt); 166 return asn1_template_ex_i2d(pchval, out, chtt, 167 -1, aclass); 168 } 169 /* Fixme: error condition if selector out of range */ 170 if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 171 return 0; 172 break; 173 174 case ASN1_ITYPE_EXTERN: 175 /* If new style i2d it does all the work */ 176 ef = it->funcs; 177 return ef->asn1_ex_i2d(pval, out, it, tag, aclass); 178 179 case ASN1_ITYPE_NDEF_SEQUENCE: 180 /* Use indefinite length constructed if requested */ 181 if (aclass & ASN1_TFLG_NDEF) 182 ndef = 2; 183 /* fall through */ 184 185 case ASN1_ITYPE_SEQUENCE: 186 i = asn1_enc_restore(&seqcontlen, out, pval, it); 187 /* An error occurred */ 188 if (i < 0) 189 return 0; 190 /* We have a valid cached encoding... */ 191 if (i > 0) 192 return seqcontlen; 193 /* Otherwise carry on */ 194 seqcontlen = 0; 195 /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ 196 if (tag == -1) { 197 tag = V_ASN1_SEQUENCE; 198 /* Retain any other flags in aclass */ 199 aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) | 200 V_ASN1_UNIVERSAL; 201 } 202 if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 203 return 0; 204 /* First work out sequence content length */ 205 for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 206 const ASN1_TEMPLATE *seqtt; 207 ASN1_VALUE **pseqval; 208 seqtt = asn1_do_adb(pval, tt, 1); 209 if (!seqtt) 210 return 0; 211 pseqval = asn1_get_field_ptr(pval, seqtt); 212 /* FIXME: check for errors in enhanced version */ 213 seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, 214 -1, aclass); 215 } 216 217 seqlen = ASN1_object_size(ndef, seqcontlen, tag); 218 if (!out) 219 return seqlen; 220 /* Output SEQUENCE header */ 221 ASN1_put_object(out, ndef, seqcontlen, tag, aclass); 222 for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 223 const ASN1_TEMPLATE *seqtt; 224 ASN1_VALUE **pseqval; 225 seqtt = asn1_do_adb(pval, tt, 1); 226 if (!seqtt) 227 return 0; 228 pseqval = asn1_get_field_ptr(pval, seqtt); 229 /* FIXME: check for errors in enhanced version */ 230 asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); 231 } 232 if (ndef == 2) 233 ASN1_put_eoc(out); 234 if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 235 return 0; 236 return seqlen; 237 238 default: 239 return 0; 240 241 } 242 return 0; 243 } 244 245 int 246 ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, 247 const ASN1_TEMPLATE *tt) 248 { 249 return asn1_template_ex_i2d(pval, out, tt, -1, 0); 250 } 251 252 static int 253 asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 254 const ASN1_TEMPLATE *tt, int tag, int iclass) 255 { 256 int i, ret, flags, ttag, tclass, ndef; 257 flags = tt->flags; 258 /* Work out tag and class to use: tagging may come 259 * either from the template or the arguments, not both 260 * because this would create ambiguity. Additionally 261 * the iclass argument may contain some additional flags 262 * which should be noted and passed down to other levels. 263 */ 264 if (flags & ASN1_TFLG_TAG_MASK) { 265 /* Error if argument and template tagging */ 266 if (tag != -1) 267 /* FIXME: error code here */ 268 return -1; 269 /* Get tagging from template */ 270 ttag = tt->tag; 271 tclass = flags & ASN1_TFLG_TAG_CLASS; 272 } else if (tag != -1) { 273 /* No template tagging, get from arguments */ 274 ttag = tag; 275 tclass = iclass & ASN1_TFLG_TAG_CLASS; 276 } else { 277 ttag = -1; 278 tclass = 0; 279 } 280 /* 281 * Remove any class mask from iflag. 282 */ 283 iclass &= ~ASN1_TFLG_TAG_CLASS; 284 285 /* At this point 'ttag' contains the outer tag to use, 286 * 'tclass' is the class and iclass is any flags passed 287 * to this function. 288 */ 289 290 /* if template and arguments require ndef, use it */ 291 if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) 292 ndef = 2; 293 else 294 ndef = 1; 295 296 if (flags & ASN1_TFLG_SK_MASK) { 297 /* SET OF, SEQUENCE OF */ 298 STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; 299 int isset, sktag, skaclass; 300 int skcontlen, sklen; 301 ASN1_VALUE *skitem; 302 303 if (!*pval) 304 return 0; 305 306 if (flags & ASN1_TFLG_SET_OF) { 307 isset = 1; 308 /* 2 means we reorder */ 309 if (flags & ASN1_TFLG_SEQUENCE_OF) 310 isset = 2; 311 } else 312 isset = 0; 313 314 /* Work out inner tag value: if EXPLICIT 315 * or no tagging use underlying type. 316 */ 317 if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) { 318 sktag = ttag; 319 skaclass = tclass; 320 } else { 321 skaclass = V_ASN1_UNIVERSAL; 322 if (isset) 323 sktag = V_ASN1_SET; 324 else 325 sktag = V_ASN1_SEQUENCE; 326 } 327 328 /* Determine total length of items */ 329 skcontlen = 0; 330 for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 331 skitem = sk_ASN1_VALUE_value(sk, i); 332 skcontlen += ASN1_item_ex_i2d(&skitem, NULL, 333 tt->item, -1, iclass); 334 } 335 sklen = ASN1_object_size(ndef, skcontlen, sktag); 336 /* If EXPLICIT need length of surrounding tag */ 337 if (flags & ASN1_TFLG_EXPTAG) 338 ret = ASN1_object_size(ndef, sklen, ttag); 339 else 340 ret = sklen; 341 342 if (!out) 343 return ret; 344 345 /* Now encode this lot... */ 346 /* EXPLICIT tag */ 347 if (flags & ASN1_TFLG_EXPTAG) 348 ASN1_put_object(out, ndef, sklen, ttag, tclass); 349 /* SET or SEQUENCE and IMPLICIT tag */ 350 ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); 351 /* And the stuff itself */ 352 asn1_set_seq_out(sk, out, skcontlen, tt->item, 353 isset, iclass); 354 if (ndef == 2) { 355 ASN1_put_eoc(out); 356 if (flags & ASN1_TFLG_EXPTAG) 357 ASN1_put_eoc(out); 358 } 359 360 return ret; 361 } 362 363 if (flags & ASN1_TFLG_EXPTAG) { 364 /* EXPLICIT tagging */ 365 /* Find length of tagged item */ 366 i = ASN1_item_ex_i2d(pval, NULL, tt->item, 367 -1, iclass); 368 if (!i) 369 return 0; 370 /* Find length of EXPLICIT tag */ 371 ret = ASN1_object_size(ndef, i, ttag); 372 if (out) { 373 /* Output tag and item */ 374 ASN1_put_object(out, ndef, i, ttag, tclass); 375 ASN1_item_ex_i2d(pval, out, tt->item, 376 -1, iclass); 377 if (ndef == 2) 378 ASN1_put_eoc(out); 379 } 380 return ret; 381 } 382 383 /* Either normal or IMPLICIT tagging: combine class and flags */ 384 return ASN1_item_ex_i2d(pval, out, tt->item, 385 ttag, tclass | iclass); 386 } 387 388 /* Temporary structure used to hold DER encoding of items for SET OF */ 389 390 typedef struct { 391 unsigned char *data; 392 int length; 393 ASN1_VALUE *field; 394 } DER_ENC; 395 396 static int 397 der_cmp(const void *a, const void *b) 398 { 399 const DER_ENC *d1 = a, *d2 = b; 400 int cmplen, i; 401 402 cmplen = (d1->length < d2->length) ? d1->length : d2->length; 403 i = memcmp(d1->data, d2->data, cmplen); 404 if (i) 405 return i; 406 return d1->length - d2->length; 407 } 408 409 /* Output the content octets of SET OF or SEQUENCE OF */ 410 411 static int 412 asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int skcontlen, 413 const ASN1_ITEM *item, int do_sort, int iclass) 414 { 415 int i; 416 ASN1_VALUE *skitem; 417 unsigned char *tmpdat = NULL, *p = NULL; 418 DER_ENC *derlst = NULL, *tder; 419 420 if (do_sort) { 421 /* Don't need to sort less than 2 items */ 422 if (sk_ASN1_VALUE_num(sk) < 2) 423 do_sort = 0; 424 else { 425 derlst = reallocarray(NULL, sk_ASN1_VALUE_num(sk), 426 sizeof(*derlst)); 427 tmpdat = malloc(skcontlen); 428 if (!derlst || !tmpdat) { 429 free(derlst); 430 free(tmpdat); 431 return 0; 432 } 433 } 434 } 435 /* If not sorting just output each item */ 436 if (!do_sort) { 437 for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 438 skitem = sk_ASN1_VALUE_value(sk, i); 439 ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); 440 } 441 return 1; 442 } 443 p = tmpdat; 444 445 /* Doing sort: build up a list of each member's DER encoding */ 446 for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 447 skitem = sk_ASN1_VALUE_value(sk, i); 448 tder->data = p; 449 tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); 450 tder->field = skitem; 451 } 452 453 /* Now sort them */ 454 qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); 455 /* Output sorted DER encoding */ 456 p = *out; 457 for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 458 memcpy(p, tder->data, tder->length); 459 p += tder->length; 460 } 461 *out = p; 462 /* If do_sort is 2 then reorder the STACK */ 463 if (do_sort == 2) { 464 for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) 465 (void)sk_ASN1_VALUE_set(sk, i, tder->field); 466 } 467 free(derlst); 468 free(tmpdat); 469 return 1; 470 } 471 472 static int 473 asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, 474 const ASN1_ITEM *it, int tag, int aclass) 475 { 476 int len; 477 int utype; 478 int usetag; 479 int ndef = 0; 480 481 utype = it->utype; 482 483 /* Get length of content octets and maybe find 484 * out the underlying type. 485 */ 486 487 len = asn1_ex_i2c(pval, NULL, &utype, it); 488 489 /* If SEQUENCE, SET or OTHER then header is 490 * included in pseudo content octets so don't 491 * include tag+length. We need to check here 492 * because the call to asn1_ex_i2c() could change 493 * utype. 494 */ 495 if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || 496 (utype == V_ASN1_OTHER)) 497 usetag = 0; 498 else 499 usetag = 1; 500 501 /* -1 means omit type */ 502 if (len == -1) 503 return 0; 504 505 /* -2 return is special meaning use ndef */ 506 if (len == -2) { 507 ndef = 2; 508 len = 0; 509 } 510 511 /* If not implicitly tagged get tag from underlying type */ 512 if (tag == -1) 513 tag = utype; 514 515 /* Output tag+length followed by content octets */ 516 if (out) { 517 if (usetag) 518 ASN1_put_object(out, ndef, len, tag, aclass); 519 asn1_ex_i2c(pval, *out, &utype, it); 520 if (ndef) 521 ASN1_put_eoc(out); 522 else 523 *out += len; 524 } 525 526 if (usetag) 527 return ASN1_object_size(ndef, len, tag); 528 return len; 529 } 530 531 /* Produce content octets from a structure */ 532 533 static int 534 asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, 535 const ASN1_ITEM *it) 536 { 537 ASN1_BOOLEAN *tbool = NULL; 538 ASN1_STRING *strtmp; 539 ASN1_OBJECT *otmp; 540 int utype; 541 const unsigned char *cont; 542 unsigned char c; 543 int len; 544 545 if (it->funcs != NULL) { 546 const ASN1_PRIMITIVE_FUNCS *pf = it->funcs; 547 548 if (pf->prim_i2c == NULL) 549 return -1; 550 return pf->prim_i2c(pval, cout, putype, it); 551 } 552 553 /* Should type be omitted? */ 554 if ((it->itype != ASN1_ITYPE_PRIMITIVE) || 555 (it->utype != V_ASN1_BOOLEAN)) { 556 if (!*pval) 557 return -1; 558 } 559 560 if (it->itype == ASN1_ITYPE_MSTRING) { 561 /* If MSTRING type set the underlying type */ 562 strtmp = (ASN1_STRING *)*pval; 563 utype = strtmp->type; 564 *putype = utype; 565 } else if (it->utype == V_ASN1_ANY) { 566 /* If ANY set type and pointer to value */ 567 ASN1_TYPE *typ; 568 typ = (ASN1_TYPE *)*pval; 569 utype = typ->type; 570 *putype = utype; 571 pval = &typ->value.asn1_value; 572 } else 573 utype = *putype; 574 575 switch (utype) { 576 case V_ASN1_OBJECT: 577 otmp = (ASN1_OBJECT *)*pval; 578 cont = otmp->data; 579 len = otmp->length; 580 break; 581 582 case V_ASN1_NULL: 583 cont = NULL; 584 len = 0; 585 break; 586 587 case V_ASN1_BOOLEAN: 588 tbool = (ASN1_BOOLEAN *)pval; 589 if (*tbool == -1) 590 return -1; 591 if (it->utype != V_ASN1_ANY) { 592 /* Default handling if value == size field then omit */ 593 if (*tbool && (it->size > 0)) 594 return -1; 595 if (!*tbool && !it->size) 596 return -1; 597 } 598 c = (unsigned char)*tbool; 599 cont = &c; 600 len = 1; 601 break; 602 603 case V_ASN1_BIT_STRING: 604 return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, 605 cout ? &cout : NULL); 606 break; 607 608 case V_ASN1_INTEGER: 609 case V_ASN1_ENUMERATED: 610 /* These are all have the same content format 611 * as ASN1_INTEGER 612 */ 613 return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, 614 cout ? &cout : NULL); 615 break; 616 617 case V_ASN1_OCTET_STRING: 618 case V_ASN1_NUMERICSTRING: 619 case V_ASN1_PRINTABLESTRING: 620 case V_ASN1_T61STRING: 621 case V_ASN1_VIDEOTEXSTRING: 622 case V_ASN1_IA5STRING: 623 case V_ASN1_UTCTIME: 624 case V_ASN1_GENERALIZEDTIME: 625 case V_ASN1_GRAPHICSTRING: 626 case V_ASN1_VISIBLESTRING: 627 case V_ASN1_GENERALSTRING: 628 case V_ASN1_UNIVERSALSTRING: 629 case V_ASN1_BMPSTRING: 630 case V_ASN1_UTF8STRING: 631 case V_ASN1_SEQUENCE: 632 case V_ASN1_SET: 633 default: 634 /* All based on ASN1_STRING and handled the same */ 635 strtmp = (ASN1_STRING *)*pval; 636 /* Special handling for NDEF */ 637 if ((it->size == ASN1_TFLG_NDEF) && 638 (strtmp->flags & ASN1_STRING_FLAG_NDEF)) { 639 if (cout) { 640 strtmp->data = cout; 641 strtmp->length = 0; 642 } 643 /* Special return code */ 644 return -2; 645 } 646 cont = strtmp->data; 647 len = strtmp->length; 648 649 break; 650 651 } 652 if (cout && len) 653 memcpy(cout, cont, len); 654 return len; 655 } 656