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