1139749Simp/* tasn_enc.c */ 2119917Swpaul/* 3119917Swpaul * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4139749Simp * 2000. 5119917Swpaul */ 6119917Swpaul/* ==================================================================== 7119917Swpaul * Copyright (c) 2000-2004 The OpenSSL Project. All rights reserved. 8119917Swpaul * 9119917Swpaul * Redistribution and use in source and binary forms, with or without 10119917Swpaul * modification, are permitted provided that the following conditions 11119917Swpaul * are met: 12119917Swpaul * 13119917Swpaul * 1. Redistributions of source code must retain the above copyright 14119917Swpaul * notice, this list of conditions and the following disclaimer. 15119917Swpaul * 16119917Swpaul * 2. Redistributions in binary form must reproduce the above copyright 17119917Swpaul * notice, this list of conditions and the following disclaimer in 18119917Swpaul * the documentation and/or other materials provided with the 19119917Swpaul * distribution. 20119917Swpaul * 21119917Swpaul * 3. All advertising materials mentioning features or use of this 22119917Swpaul * software must display the following acknowledgment: 23119917Swpaul * "This product includes software developed by the OpenSSL Project 24119917Swpaul * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25119917Swpaul * 26119917Swpaul * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27119917Swpaul * endorse or promote products derived from this software without 28119917Swpaul * prior written permission. For written permission, please contact 29119917Swpaul * licensing@OpenSSL.org. 30119917Swpaul * 31119917Swpaul * 5. Products derived from this software may not be called "OpenSSL" 32119917Swpaul * nor may "OpenSSL" appear in their names without prior written 33119917Swpaul * permission of the OpenSSL Project. 34119917Swpaul * 35119917Swpaul * 6. Redistributions of any form whatsoever must retain the following 36119917Swpaul * acknowledgment: 37129879Sphk * "This product includes software developed by the OpenSSL Project 38119917Swpaul * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39119917Swpaul * 40119917Swpaul * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41119917Swpaul * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42119917Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43119917Swpaul * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44119917Swpaul * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45119917Swpaul * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46119917Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47119917Swpaul * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48119917Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49119917Swpaul * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50119917Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51119917Swpaul * OF THE POSSIBILITY OF SUCH DAMAGE. 52119917Swpaul * ==================================================================== 53119917Swpaul * 54119917Swpaul * This product includes cryptographic software written by Eric Young 55119917Swpaul * (eay@cryptsoft.com). This product includes software written by Tim 56119917Swpaul * Hudson (tjh@cryptsoft.com). 57119917Swpaul * 58119917Swpaul */ 59119917Swpaul 60119917Swpaul#include <stddef.h> 61119917Swpaul#include <string.h> 62119917Swpaul#include "cryptlib.h" 63119917Swpaul#include <openssl/asn1.h> 64119917Swpaul#include <openssl/asn1t.h> 65119917Swpaul#include <openssl/objects.h> 66119917Swpaul 67119917Swpaulstatic int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, 68119917Swpaul const ASN1_ITEM *it, int tag, int aclass); 69119917Swpaulstatic int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, 70119917Swpaul int skcontlen, const ASN1_ITEM *item, 71119917Swpaul int do_sort, int iclass); 72119917Swpaulstatic int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 73119917Swpaul const ASN1_TEMPLATE *tt, int tag, int aclass); 74151545Simpstatic int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, 75119917Swpaul const ASN1_ITEM *it, int flags); 76119917Swpaul 77119917Swpaul/* 78119917Swpaul * Top level i2d equivalents: the 'ndef' variant instructs the encoder to use 79119917Swpaul * indefinite length constructed encoding, where appropriate 80119917Swpaul */ 81119917Swpaul 82134590Sdesint ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, 83134590Sdes const ASN1_ITEM *it) 84119917Swpaul{ 85119917Swpaul return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); 86119917Swpaul} 87119917Swpaul 88119917Swpaulint ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) 89119917Swpaul{ 90164456Sjhb return asn1_item_flags_i2d(val, out, it, 0); 91164456Sjhb} 92119917Swpaul 93119917Swpaul/* 94119917Swpaul * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out' 95136804Smtm * points to a buffer to output the data to. The new i2d has one additional 96119917Swpaul * feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is 97119917Swpaul * allocated and populated with the encoding. 98136804Smtm */ 99119917Swpaul 100175787Syongaristatic int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, 101173839Syongari const ASN1_ITEM *it, int flags) 102119917Swpaul{ 103119917Swpaul if (out && !*out) { 104119917Swpaul unsigned char *p, *buf; 105119917Swpaul int len; 106119917Swpaul len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); 107119917Swpaul if (len <= 0) 108119917Swpaul return len; 109119917Swpaul buf = OPENSSL_malloc(len); 110119917Swpaul if (!buf) 111119917Swpaul return -1; 112119917Swpaul p = buf; 113119917Swpaul ASN1_item_ex_i2d(&val, &p, it, -1, flags); 114119917Swpaul *out = buf; 115119917Swpaul return len; 116133282Sdes } 117119917Swpaul 118119917Swpaul return ASN1_item_ex_i2d(&val, out, it, -1, flags); 119119917Swpaul} 120119917Swpaul 121119917Swpaul/* 122119917Swpaul * Encode an item, taking care of IMPLICIT tagging (if any). This function 123119917Swpaul * performs the normal item handling: it can be used in external types. 124119917Swpaul */ 125119917Swpaul 126119917Swpaulint ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 127119917Swpaul const ASN1_ITEM *it, int tag, int aclass) 128119917Swpaul{ 129119917Swpaul const ASN1_TEMPLATE *tt = NULL; 130119917Swpaul unsigned char *p = NULL; 131119917Swpaul int i, seqcontlen, seqlen, ndef = 1; 132119917Swpaul const ASN1_COMPAT_FUNCS *cf; 133119917Swpaul const ASN1_EXTERN_FUNCS *ef; 134119917Swpaul const ASN1_AUX *aux = it->funcs; 135119917Swpaul ASN1_aux_cb *asn1_cb = 0; 136119917Swpaul 137119917Swpaul if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) 138119917Swpaul return 0; 139119917Swpaul 140119917Swpaul if (aux && aux->asn1_cb) 141164456Sjhb asn1_cb = aux->asn1_cb; 142164456Sjhb 143119917Swpaul switch (it->itype) { 144119917Swpaul 145119917Swpaul case ASN1_ITYPE_PRIMITIVE: 146119917Swpaul if (it->templates) 147119917Swpaul return asn1_template_ex_i2d(pval, out, it->templates, 148119917Swpaul tag, aclass); 149119917Swpaul return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); 150119917Swpaul break; 151119917Swpaul 152119917Swpaul case ASN1_ITYPE_MSTRING: 153119917Swpaul return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); 154119917Swpaul 155119917Swpaul case ASN1_ITYPE_CHOICE: 156119917Swpaul if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 157119917Swpaul return 0; 158119917Swpaul i = asn1_get_choice_selector(pval, it); 159119917Swpaul if ((i >= 0) && (i < it->tcount)) { 160119917Swpaul ASN1_VALUE **pchval; 161119917Swpaul const ASN1_TEMPLATE *chtt; 162119917Swpaul chtt = it->templates + i; 163119917Swpaul pchval = asn1_get_field_ptr(pval, chtt); 164119917Swpaul return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass); 165119917Swpaul } 166119917Swpaul /* Fixme: error condition if selector out of range */ 167119917Swpaul if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 168133282Sdes return 0; 169119917Swpaul break; 170119917Swpaul 171119917Swpaul case ASN1_ITYPE_EXTERN: 172119917Swpaul /* If new style i2d it does all the work */ 173119917Swpaul ef = it->funcs; 174119917Swpaul return ef->asn1_ex_i2d(pval, out, it, tag, aclass); 175119917Swpaul 176119917Swpaul case ASN1_ITYPE_COMPAT: 177180954Syongari /* old style hackery... */ 178181556Syongari cf = it->funcs; 179181556Syongari if (out) 180119917Swpaul p = *out; 181143163Simp i = cf->asn1_i2d(*pval, out); 182119917Swpaul /* 183119917Swpaul * Fixup for IMPLICIT tag: note this messes up for tags > 30, but so 184119917Swpaul * did the old code. Tags > 30 are very rare anyway. 185119917Swpaul */ 186133282Sdes if (out && (tag != -1)) 187119917Swpaul *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); 188119917Swpaul return i; 189119917Swpaul 190119917Swpaul case ASN1_ITYPE_NDEF_SEQUENCE: 191119917Swpaul /* Use indefinite length constructed if requested */ 192119917Swpaul if (aclass & ASN1_TFLG_NDEF) 193119917Swpaul ndef = 2; 194119917Swpaul /* fall through */ 195119917Swpaul 196119917Swpaul case ASN1_ITYPE_SEQUENCE: 197158075Sscottl i = asn1_enc_restore(&seqcontlen, out, pval, it); 198158075Sscottl /* An error occurred */ 199158075Sscottl if (i < 0) 200158075Sscottl return 0; 201119917Swpaul /* We have a valid cached encoding... */ 202159013Ssilby if (i > 0) 203158103Ssilby return seqcontlen; 204158075Sscottl /* Otherwise carry on */ 205119917Swpaul seqcontlen = 0; 206119917Swpaul /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ 207119917Swpaul if (tag == -1) { 208119917Swpaul tag = V_ASN1_SEQUENCE; 209159021Ssilby /* Retain any other flags in aclass */ 210119917Swpaul aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) 211119917Swpaul | V_ASN1_UNIVERSAL; 212119917Swpaul } 213119917Swpaul if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) 214126470Sjulian return 0; 215159013Ssilby /* First work out sequence content length */ 216126470Sjulian for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 217133282Sdes const ASN1_TEMPLATE *seqtt; 218126470Sjulian ASN1_VALUE **pseqval; 219126470Sjulian seqtt = asn1_do_adb(pval, tt, 1); 220126470Sjulian if (!seqtt) 221126470Sjulian return 0; 222159021Ssilby pseqval = asn1_get_field_ptr(pval, seqtt); 223126470Sjulian /* FIXME: check for errors in enhanced version */ 224126470Sjulian seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, 225119917Swpaul -1, aclass); 226119917Swpaul } 227119917Swpaul 228133282Sdes seqlen = ASN1_object_size(ndef, seqcontlen, tag); 229119917Swpaul if (!out) 230119917Swpaul return seqlen; 231119917Swpaul /* Output SEQUENCE header */ 232126470Sjulian ASN1_put_object(out, ndef, seqcontlen, tag, aclass); 233159013Ssilby for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) { 234126470Sjulian const ASN1_TEMPLATE *seqtt; 235126470Sjulian ASN1_VALUE **pseqval; 236126470Sjulian seqtt = asn1_do_adb(pval, tt, 1); 237126470Sjulian if (!seqtt) 238126470Sjulian return 0; 239126470Sjulian pseqval = asn1_get_field_ptr(pval, seqtt); 240159021Ssilby /* FIXME: check for errors in enhanced version */ 241126470Sjulian asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); 242126470Sjulian } 243119917Swpaul if (ndef == 2) 244119917Swpaul ASN1_put_eoc(out); 245119917Swpaul if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) 246133282Sdes return 0; 247119917Swpaul return seqlen; 248119917Swpaul 249119917Swpaul default: 250126470Sjulian return 0; 251126470Sjulian 252126470Sjulian } 253126470Sjulian return 0; 254126470Sjulian} 255126470Sjulian 256126470Sjulianint ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, 257126470Sjulian const ASN1_TEMPLATE *tt) 258158075Sscottl{ 259126470Sjulian return asn1_template_ex_i2d(pval, out, tt, -1, 0); 260126470Sjulian} 261119917Swpaul 262119917Swpaulstatic int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, 263119917Swpaul const ASN1_TEMPLATE *tt, int tag, int iclass) 264133282Sdes{ 265119917Swpaul int i, ret, flags, ttag, tclass, ndef; 266119917Swpaul flags = tt->flags; 267119917Swpaul /* 268119917Swpaul * Work out tag and class to use: tagging may come either from the 269126470Sjulian * template or the arguments, not both because this would create 270126470Sjulian * ambiguity. Additionally the iclass argument may contain some 271119917Swpaul * additional flags which should be noted and passed down to other 272119917Swpaul * levels. 273133282Sdes */ 274119917Swpaul if (flags & ASN1_TFLG_TAG_MASK) { 275119917Swpaul /* Error if argument and template tagging */ 276119917Swpaul if (tag != -1) 277119917Swpaul /* FIXME: error code here */ 278119917Swpaul return -1; 279126470Sjulian /* Get tagging from template */ 280126470Sjulian ttag = tt->tag; 281119917Swpaul tclass = flags & ASN1_TFLG_TAG_CLASS; 282119917Swpaul } else if (tag != -1) { 283133282Sdes /* No template tagging, get from arguments */ 284119917Swpaul ttag = tag; 285119917Swpaul tclass = iclass & ASN1_TFLG_TAG_CLASS; 286119917Swpaul } else { 287119917Swpaul ttag = -1; 288119917Swpaul tclass = 0; 289119917Swpaul } 290119917Swpaul /* 291180954Syongari * Remove any class mask from iflag. 292133282Sdes */ 293119917Swpaul iclass &= ~ASN1_TFLG_TAG_CLASS; 294119917Swpaul 295119917Swpaul /* 296119917Swpaul * At this point 'ttag' contains the outer tag to use, 'tclass' is the 297158285Ssilby * class and iclass is any flags passed to this function. 298119917Swpaul */ 299180954Syongari 300133282Sdes /* if template and arguments require ndef, use it */ 301119917Swpaul if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) 302158102Ssilby ndef = 2; 303119917Swpaul else 304133282Sdes ndef = 1; 305119917Swpaul 306133282Sdes if (flags & ASN1_TFLG_SK_MASK) { 307133282Sdes /* SET OF, SEQUENCE OF */ 308119917Swpaul STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; 309119917Swpaul int isset, sktag, skaclass; 310133282Sdes int skcontlen, sklen; 311133282Sdes ASN1_VALUE *skitem; 312158285Ssilby 313180954Syongari if (!*pval) 314133282Sdes return 0; 315119917Swpaul 316119917Swpaul if (flags & ASN1_TFLG_SET_OF) { 317158102Ssilby isset = 1; 318119917Swpaul /* 2 means we reorder */ 319133282Sdes if (flags & ASN1_TFLG_SEQUENCE_OF) 320119917Swpaul isset = 2; 321119917Swpaul } else 322119917Swpaul isset = 0; 323119917Swpaul 324119917Swpaul /* 325147256Sbrooks * Work out inner tag value: if EXPLICIT or no tagging use underlying 326119917Swpaul * type. 327180950Syongari */ 328119917Swpaul if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) { 329119917Swpaul sktag = ttag; 330119917Swpaul skaclass = tclass; 331136804Smtm } else { 332175787Syongari skaclass = V_ASN1_UNIVERSAL; 333119917Swpaul if (isset) 334119917Swpaul sktag = V_ASN1_SET; 335119917Swpaul else 336119917Swpaul sktag = V_ASN1_SEQUENCE; 337119917Swpaul } 338119917Swpaul 339119917Swpaul /* Determine total length of items */ 340119917Swpaul skcontlen = 0; 341119917Swpaul for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 342127135Snjl skitem = sk_ASN1_VALUE_value(sk, i); 343119917Swpaul skcontlen += ASN1_item_ex_i2d(&skitem, NULL, 344119917Swpaul ASN1_ITEM_ptr(tt->item), 345180950Syongari -1, iclass); 346119917Swpaul } 347119917Swpaul sklen = ASN1_object_size(ndef, skcontlen, sktag); 348119917Swpaul /* If EXPLICIT need length of surrounding tag */ 349119917Swpaul if (flags & ASN1_TFLG_EXPTAG) 350119917Swpaul ret = ASN1_object_size(ndef, sklen, ttag); 351119917Swpaul else 352119917Swpaul ret = sklen; 353119917Swpaul 354119917Swpaul if (!out) 355119917Swpaul return ret; 356119917Swpaul 357127135Snjl /* Now encode this lot... */ 358119917Swpaul /* EXPLICIT tag */ 359119917Swpaul if (flags & ASN1_TFLG_EXPTAG) 360180950Syongari ASN1_put_object(out, ndef, sklen, ttag, tclass); 361119917Swpaul /* SET or SEQUENCE and IMPLICIT tag */ 362119917Swpaul ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); 363119917Swpaul /* And the stuff itself */ 364119917Swpaul asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), 365119917Swpaul isset, iclass); 366180950Syongari if (ndef == 2) { 367119917Swpaul ASN1_put_eoc(out); 368119917Swpaul if (flags & ASN1_TFLG_EXPTAG) 369119917Swpaul ASN1_put_eoc(out); 370119917Swpaul } 371119917Swpaul 372147256Sbrooks return ret; 373147256Sbrooks } 374180950Syongari 375147256Sbrooks if (flags & ASN1_TFLG_EXPTAG) { 376147256Sbrooks /* EXPLICIT tagging */ 377147256Sbrooks /* Find length of tagged item */ 378119917Swpaul i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass); 379121816Sbrooks if (!i) 380119917Swpaul return 0; 381119917Swpaul /* Find length of EXPLICIT tag */ 382119917Swpaul ret = ASN1_object_size(ndef, i, ttag); 383119917Swpaul if (out) { 384119917Swpaul /* Output tag and item */ 385131455Smlaier ASN1_put_object(out, ndef, i, ttag, tclass); 386131455Smlaier ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass); 387131455Smlaier if (ndef == 2) 388119917Swpaul ASN1_put_eoc(out); 389119917Swpaul } 390119917Swpaul return ret; 391119917Swpaul } 392136804Smtm 393119917Swpaul /* Either normal or IMPLICIT tagging: combine class and flags */ 394136804Smtm return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), 395119917Swpaul ttag, tclass | iclass); 396119917Swpaul 397119917Swpaul} 398180950Syongari 399119917Swpaul/* Temporary structure used to hold DER encoding of items for SET OF */ 400119917Swpaul 401119917Swpaultypedef struct { 402119917Swpaul unsigned char *data; 403147256Sbrooks int length; 404119917Swpaul ASN1_VALUE *field; 405119917Swpaul} DER_ENC; 406129708Sdes 407129708Sdesstatic int der_cmp(const void *a, const void *b) 408129708Sdes{ 409129708Sdes const DER_ENC *d1 = a, *d2 = b; 410129709Sdes int cmplen, i; 411129708Sdes cmplen = (d1->length < d2->length) ? d1->length : d2->length; 412129708Sdes i = memcmp(d1->data, d2->data, cmplen); 413119917Swpaul if (i) 414119917Swpaul return i; 415136804Smtm return d1->length - d2->length; 416166901Spiso} 417119917Swpaul 418119917Swpaul/* Output the content octets of SET OF or SEQUENCE OF */ 419180950Syongari 420119917Swpaulstatic int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, 421119917Swpaul int skcontlen, const ASN1_ITEM *item, 422119917Swpaul int do_sort, int iclass) 423150215Sru{ 424119917Swpaul int i; 425133282Sdes ASN1_VALUE *skitem; 426119917Swpaul unsigned char *tmpdat = NULL, *p = NULL; 427119917Swpaul DER_ENC *derlst = NULL, *tder; 428119917Swpaul if (do_sort) { 429119917Swpaul /* Don't need to sort less than 2 items */ 430119917Swpaul if (sk_ASN1_VALUE_num(sk) < 2) 431119917Swpaul do_sort = 0; 432119917Swpaul else { 433119917Swpaul derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) 434119917Swpaul * sizeof(*derlst)); 435119917Swpaul if (!derlst) 436119917Swpaul return 0; 437119917Swpaul tmpdat = OPENSSL_malloc(skcontlen); 438147256Sbrooks if (!tmpdat) { 439119917Swpaul OPENSSL_free(derlst); 440119917Swpaul return 0; 441175787Syongari } 442119917Swpaul } 443175787Syongari } 444175787Syongari /* If not sorting just output each item */ 445175787Syongari if (!do_sort) { 446175787Syongari for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { 447119917Swpaul skitem = sk_ASN1_VALUE_value(sk, i); 448119917Swpaul ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); 449119917Swpaul } 450119917Swpaul return 1; 451119917Swpaul } 452180954Syongari p = tmpdat; 453119917Swpaul 454119917Swpaul /* Doing sort: build up a list of each member's DER encoding */ 455119917Swpaul for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 456119917Swpaul skitem = sk_ASN1_VALUE_value(sk, i); 457119917Swpaul tder->data = p; 458133282Sdes tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); 459119917Swpaul tder->field = skitem; 460119917Swpaul } 461119917Swpaul 462119917Swpaul /* Now sort them */ 463119917Swpaul qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); 464119917Swpaul /* Output sorted DER encoding */ 465173839Syongari p = *out; 466119917Swpaul for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) { 467119917Swpaul memcpy(p, tder->data, tder->length); 468119917Swpaul p += tder->length; 469119917Swpaul } 470119917Swpaul *out = p; 471119917Swpaul /* If do_sort is 2 then reorder the STACK */ 472133282Sdes if (do_sort == 2) { 473119917Swpaul for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) 474119917Swpaul (void)sk_ASN1_VALUE_set(sk, i, tder->field); 475173839Syongari } 476173839Syongari OPENSSL_free(derlst); 477119917Swpaul OPENSSL_free(tmpdat); 478119917Swpaul return 1; 479119917Swpaul} 480164456Sjhb 481164456Sjhbstatic int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, 482164456Sjhb const ASN1_ITEM *it, int tag, int aclass) 483164456Sjhb{ 484164456Sjhb int len; 485164456Sjhb int utype; 486164456Sjhb int usetag; 487164456Sjhb int ndef = 0; 488164456Sjhb 489164456Sjhb utype = it->utype; 490164456Sjhb 491164456Sjhb /* 492164456Sjhb * Get length of content octets and maybe find out the underlying type. 493164456Sjhb */ 494164456Sjhb 495164456Sjhb len = asn1_ex_i2c(pval, NULL, &utype, it); 496164456Sjhb 497164456Sjhb /* 498164456Sjhb * If SEQUENCE, SET or OTHER then header is included in pseudo content 499164456Sjhb * octets so don't include tag+length. We need to check here because the 500164456Sjhb * call to asn1_ex_i2c() could change utype. 501164456Sjhb */ 502164456Sjhb if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || 503164456Sjhb (utype == V_ASN1_OTHER)) 504164456Sjhb usetag = 0; 505164456Sjhb else 506164456Sjhb usetag = 1; 507164456Sjhb 508164456Sjhb /* -1 means omit type */ 509164456Sjhb 510164456Sjhb if (len == -1) 511164456Sjhb return 0; 512164456Sjhb 513164456Sjhb /* -2 return is special meaning use ndef */ 514119917Swpaul if (len == -2) { 515119917Swpaul ndef = 2; 516119917Swpaul len = 0; 517119917Swpaul } 518119917Swpaul 519119917Swpaul /* If not implicitly tagged get tag from underlying type */ 520180954Syongari if (tag == -1) 521133282Sdes tag = utype; 522119917Swpaul 523119917Swpaul /* Output tag+length followed by content octets */ 524133282Sdes if (out) { 525119917Swpaul if (usetag) 526119917Swpaul ASN1_put_object(out, ndef, len, tag, aclass); 527119917Swpaul asn1_ex_i2c(pval, *out, &utype, it); 528119917Swpaul if (ndef) 529119917Swpaul ASN1_put_eoc(out); 530119917Swpaul else 531119917Swpaul *out += len; 532119917Swpaul } 533180954Syongari 534133282Sdes if (usetag) 535133282Sdes return ASN1_object_size(ndef, len, tag); 536119917Swpaul return len; 537133282Sdes} 538119917Swpaul 539119917Swpaul/* Produce content octets from a structure */ 540119917Swpaul 541119917Swpaulint asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, 542119917Swpaul const ASN1_ITEM *it) 543175787Syongari{ 544175787Syongari ASN1_BOOLEAN *tbool = NULL; 545175787Syongari ASN1_STRING *strtmp; 546175787Syongari ASN1_OBJECT *otmp; 547175787Syongari int utype; 548175787Syongari const unsigned char *cont; 549175787Syongari unsigned char c; 550175787Syongari int len; 551175787Syongari const ASN1_PRIMITIVE_FUNCS *pf; 552175787Syongari pf = it->funcs; 553175787Syongari if (pf && pf->prim_i2c) 554175787Syongari return pf->prim_i2c(pval, cout, putype, it); 555175787Syongari 556175787Syongari /* Should type be omitted? */ 557175787Syongari if ((it->itype != ASN1_ITYPE_PRIMITIVE) 558175787Syongari || (it->utype != V_ASN1_BOOLEAN)) { 559175787Syongari if (!*pval) 560175787Syongari return -1; 561175787Syongari } 562175787Syongari 563175787Syongari if (it->itype == ASN1_ITYPE_MSTRING) { 564175787Syongari /* If MSTRING type set the underlying type */ 565175787Syongari strtmp = (ASN1_STRING *)*pval; 566175787Syongari utype = strtmp->type; 567175787Syongari *putype = utype; 568175787Syongari } else if (it->utype == V_ASN1_ANY) { 569175787Syongari /* If ANY set type and pointer to value */ 570175787Syongari ASN1_TYPE *typ; 571175787Syongari typ = (ASN1_TYPE *)*pval; 572175787Syongari utype = typ->type; 573175787Syongari *putype = utype; 574175787Syongari pval = &typ->value.asn1_value; 575175787Syongari } else 576175787Syongari utype = *putype; 577175787Syongari 578175787Syongari switch (utype) { 579119917Swpaul case V_ASN1_OBJECT: 580119917Swpaul otmp = (ASN1_OBJECT *)*pval; 581119917Swpaul cont = otmp->data; 582119917Swpaul len = otmp->length; 583119917Swpaul break; 584126470Sjulian 585133282Sdes case V_ASN1_NULL: 586126470Sjulian cont = NULL; 587180954Syongari len = 0; 588126470Sjulian break; 589126470Sjulian 590126470Sjulian case V_ASN1_BOOLEAN: 591126470Sjulian tbool = (ASN1_BOOLEAN *)pval; 592126470Sjulian if (*tbool == -1) 593126470Sjulian return -1; 594126470Sjulian if (it->utype != V_ASN1_ANY) { 595158102Ssilby /* 596119917Swpaul * Default handling if value == size field then omit 597119917Swpaul */ 598119917Swpaul if (*tbool && (it->size > 0)) 599119917Swpaul return -1; 600119917Swpaul if (!*tbool && !it->size) 601119917Swpaul return -1; 602119917Swpaul } 603119917Swpaul c = (unsigned char)*tbool; 604119917Swpaul cont = &c; 605119917Swpaul len = 1; 606119917Swpaul break; 607119917Swpaul 608119917Swpaul case V_ASN1_BIT_STRING: 609119917Swpaul return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, 610119917Swpaul cout ? &cout : NULL); 611119917Swpaul break; 612158102Ssilby 613119917Swpaul case V_ASN1_INTEGER: 614119917Swpaul case V_ASN1_ENUMERATED: 615133282Sdes /* 616119917Swpaul * These are all have the same content format as ASN1_INTEGER 617119917Swpaul */ 618119917Swpaul return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL); 619119917Swpaul break; 620119917Swpaul 621180954Syongari case V_ASN1_OCTET_STRING: 622133282Sdes case V_ASN1_NUMERICSTRING: 623119917Swpaul case V_ASN1_PRINTABLESTRING: 624119917Swpaul case V_ASN1_T61STRING: 625158102Ssilby case V_ASN1_VIDEOTEXSTRING: 626119917Swpaul case V_ASN1_IA5STRING: 627119917Swpaul case V_ASN1_UTCTIME: 628119917Swpaul case V_ASN1_GENERALIZEDTIME: 629119917Swpaul case V_ASN1_GRAPHICSTRING: 630133282Sdes case V_ASN1_VISIBLESTRING: 631119917Swpaul case V_ASN1_GENERALSTRING: 632119917Swpaul case V_ASN1_UNIVERSALSTRING: 633119917Swpaul case V_ASN1_BMPSTRING: 634119917Swpaul case V_ASN1_UTF8STRING: 635119917Swpaul case V_ASN1_SEQUENCE: 636119917Swpaul case V_ASN1_SET: 637119917Swpaul default: 638119917Swpaul /* All based on ASN1_STRING and handled the same */ 639119917Swpaul strtmp = (ASN1_STRING *)*pval; 640178687Syongari /* Special handling for NDEF */ 641119917Swpaul if ((it->size == ASN1_TFLG_NDEF) 642119917Swpaul && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) { 643133282Sdes if (cout) { 644119917Swpaul strtmp->data = cout; 645178687Syongari strtmp->length = 0; 646180954Syongari } 647119917Swpaul /* Special return code */ 648180954Syongari return -2; 649133282Sdes } 650119917Swpaul cont = strtmp->data; 651178687Syongari len = strtmp->length; 652119917Swpaul 653119917Swpaul break; 654119917Swpaul 655119917Swpaul } 656119917Swpaul if (cout && len) 657119917Swpaul memcpy(cout, cont, len); 658119917Swpaul return len; 659119917Swpaul} 660119917Swpaul