1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/asn1.h>
58 
59 #include <string.h>
60 
61 #include <openssl/asn1t.h>
62 #include <openssl/mem.h>
63 
64 
65 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
66 					const ASN1_ITEM *it,
67 					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,
70 					int do_sort, int iclass);
71 static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
72 					const ASN1_TEMPLATE *tt,
73 					int tag, int aclass);
74 static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
75 					const ASN1_ITEM *it, int flags);
76 
77 /* Top level i2d equivalents: the 'ndef' variant instructs the encoder
78  * to use indefinite length constructed encoding, where appropriate
79  */
80 
ASN1_item_ndef_i2d(ASN1_VALUE * val,unsigned char ** out,const ASN1_ITEM * it)81 int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out,
82 						const ASN1_ITEM *it)
83 	{
84 	return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
85 	}
86 
ASN1_item_i2d(ASN1_VALUE * val,unsigned char ** out,const ASN1_ITEM * it)87 int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
88 	{
89 	return asn1_item_flags_i2d(val, out, it, 0);
90 	}
91 
92 /* Encode an ASN1 item, this is use by the
93  * standard 'i2d' function. 'out' points to
94  * a buffer to output the data to.
95  *
96  * The new i2d has one additional feature. If the output
97  * buffer is NULL (i.e. *out == NULL) then a buffer is
98  * allocated and populated with the encoding.
99  */
100 
asn1_item_flags_i2d(ASN1_VALUE * val,unsigned char ** out,const ASN1_ITEM * it,int flags)101 static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
102 					const ASN1_ITEM *it, int flags)
103 	{
104 	if (out && !*out)
105 		{
106 		unsigned char *p, *buf;
107 		int len;
108 		len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
109 		if (len <= 0)
110 			return len;
111 		buf = OPENSSL_malloc(len);
112 		if (!buf)
113 			return -1;
114 		p = buf;
115 		ASN1_item_ex_i2d(&val, &p, it, -1, flags);
116 		*out = buf;
117 		return len;
118 		}
119 
120 	return ASN1_item_ex_i2d(&val, out, it, -1, flags);
121 	}
122 
123 /* Encode an item, taking care of IMPLICIT tagging (if any).
124  * This function performs the normal item handling: it can be
125  * used in external types.
126  */
127 
ASN1_item_ex_i2d(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_ITEM * it,int tag,int aclass)128 int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
129 			const ASN1_ITEM *it, int tag, int aclass)
130 	{
131 	const ASN1_TEMPLATE *tt = NULL;
132 	unsigned char *p = NULL;
133 	int i, seqcontlen, seqlen, ndef = 1;
134 	const ASN1_COMPAT_FUNCS *cf;
135 	const ASN1_EXTERN_FUNCS *ef;
136 	const ASN1_AUX *aux = it->funcs;
137 	ASN1_aux_cb *asn1_cb = 0;
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 
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 		return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
157 
158 		case ASN1_ITYPE_CHOICE:
159 		if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
160 				return 0;
161 		i = asn1_get_choice_selector(pval, it);
162 		if ((i >= 0) && (i < it->tcount))
163 			{
164 			ASN1_VALUE **pchval;
165 			const ASN1_TEMPLATE *chtt;
166 			chtt = it->templates + i;
167 			pchval = asn1_get_field_ptr(pval, chtt);
168 			return asn1_template_ex_i2d(pchval, out, chtt,
169 								-1, aclass);
170 			}
171 		/* Fixme: error condition if selector out of range */
172 		if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
173 				return 0;
174 		break;
175 
176 		case ASN1_ITYPE_EXTERN:
177 		/* If new style i2d it does all the work */
178 		ef = it->funcs;
179 		return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
180 
181 		case ASN1_ITYPE_COMPAT:
182 		/* old style hackery... */
183 		cf = it->funcs;
184 		if (out)
185 			p = *out;
186 		i = cf->asn1_i2d(*pval, out);
187 		/* Fixup for IMPLICIT tag: note this messes up for tags > 30,
188 		 * but so did the old code. Tags > 30 are very rare anyway.
189 		 */
190 		if (out && (tag != -1))
191 			*p = aclass | tag | (*p & V_ASN1_CONSTRUCTED);
192 		return i;
193 
194 		case ASN1_ITYPE_NDEF_SEQUENCE:
195 		/* Use indefinite length constructed if requested */
196 		if (aclass & ASN1_TFLG_NDEF) ndef = 2;
197 		/* fall through */
198 
199 		case ASN1_ITYPE_SEQUENCE:
200 		i = asn1_enc_restore(&seqcontlen, out, pval, it);
201 		/* An error occurred */
202 		if (i < 0)
203 			return 0;
204 		/* We have a valid cached encoding... */
205 		if (i > 0)
206 			return seqcontlen;
207 		/* Otherwise carry on */
208 		seqcontlen = 0;
209 		/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
210 		if (tag == -1)
211 			{
212 			tag = V_ASN1_SEQUENCE;
213 			/* Retain any other flags in aclass */
214 			aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
215 					| V_ASN1_UNIVERSAL;
216 			}
217 		if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
218 				return 0;
219 		/* First work out sequence content length */
220 		for (i = 0, tt = it->templates; i < it->tcount; tt++, i++)
221 			{
222 			const ASN1_TEMPLATE *seqtt;
223 			ASN1_VALUE **pseqval;
224 			seqtt = asn1_do_adb(pval, tt, 1);
225 			if (!seqtt)
226 				return 0;
227 			pseqval = asn1_get_field_ptr(pval, seqtt);
228 			/* FIXME: check for errors in enhanced version */
229 			seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
230 								-1, aclass);
231 			}
232 
233 		seqlen = ASN1_object_size(ndef, seqcontlen, tag);
234 		if (!out)
235 			return seqlen;
236 		/* Output SEQUENCE header */
237 		ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
238 		for (i = 0, tt = it->templates; i < it->tcount; tt++, i++)
239 			{
240 			const ASN1_TEMPLATE *seqtt;
241 			ASN1_VALUE **pseqval;
242 			seqtt = asn1_do_adb(pval, tt, 1);
243 			if (!seqtt)
244 				return 0;
245 			pseqval = asn1_get_field_ptr(pval, seqtt);
246 			/* FIXME: check for errors in enhanced version */
247 			asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
248 			}
249 		if (ndef == 2)
250 			ASN1_put_eoc(out);
251 		if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
252 				return 0;
253 		return seqlen;
254 
255 		default:
256 		return 0;
257 
258 		}
259 	return 0;
260 	}
261 
ASN1_template_i2d(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_TEMPLATE * tt)262 int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out,
263 							const ASN1_TEMPLATE *tt)
264 	{
265 	return asn1_template_ex_i2d(pval, out, tt, -1, 0);
266 	}
267 
asn1_template_ex_i2d(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_TEMPLATE * tt,int tag,int iclass)268 static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
269 				const ASN1_TEMPLATE *tt, int tag, int iclass)
270 	{
271 	int i, ret, flags, ttag, tclass, ndef;
272 	size_t j;
273 	flags = tt->flags;
274 	/* Work out tag and class to use: tagging may come
275 	 * either from the template or the arguments, not both
276 	 * because this would create ambiguity. Additionally
277 	 * the iclass argument may contain some additional flags
278 	 * which should be noted and passed down to other levels.
279 	 */
280 	if (flags & ASN1_TFLG_TAG_MASK)
281 		{
282 		/* Error if argument and template tagging */
283 		if (tag != -1)
284 			/* FIXME: error code here */
285 			return -1;
286 		/* Get tagging from template */
287 		ttag = tt->tag;
288 		tclass = flags & ASN1_TFLG_TAG_CLASS;
289 		}
290 	else if (tag != -1)
291 		{
292 		/* No template tagging, get from arguments */
293 		ttag = tag;
294 		tclass = iclass & ASN1_TFLG_TAG_CLASS;
295 		}
296 	else
297 		{
298 		ttag = -1;
299 		tclass = 0;
300 		}
301 	/*
302 	 * Remove any class mask from iflag.
303 	 */
304 	iclass &= ~ASN1_TFLG_TAG_CLASS;
305 
306 	/* At this point 'ttag' contains the outer tag to use,
307 	 * 'tclass' is the class and iclass is any flags passed
308 	 * to this function.
309 	 */
310 
311 	/* if template and arguments require ndef, use it */
312 	if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
313 		ndef = 2;
314 	else ndef = 1;
315 
316 	if (flags & ASN1_TFLG_SK_MASK)
317 		{
318 		/* SET OF, SEQUENCE OF */
319 		STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
320 		int isset, sktag, skaclass;
321 		int skcontlen, sklen;
322 		ASN1_VALUE *skitem;
323 
324 		if (!*pval)
325 			return 0;
326 
327 		if (flags & ASN1_TFLG_SET_OF)
328 			{
329 			isset = 1;
330 			/* 2 means we reorder */
331 			if (flags & ASN1_TFLG_SEQUENCE_OF)
332 				isset = 2;
333 			}
334 		else isset = 0;
335 
336 		/* Work out inner tag value: if EXPLICIT
337 		 * or no tagging use underlying type.
338 		 */
339 		if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG))
340 			{
341 			sktag = ttag;
342 			skaclass = tclass;
343 			}
344 		else
345 			{
346 			skaclass = V_ASN1_UNIVERSAL;
347 			if (isset)
348 				sktag = V_ASN1_SET;
349 			else sktag = V_ASN1_SEQUENCE;
350 			}
351 
352 		/* Determine total length of items */
353 		skcontlen = 0;
354 		for (j = 0; j < sk_ASN1_VALUE_num(sk); j++)
355 			{
356 			skitem = sk_ASN1_VALUE_value(sk, j);
357 			skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
358 						ASN1_ITEM_ptr(tt->item),
359 							-1, iclass);
360 			}
361 		sklen = ASN1_object_size(ndef, skcontlen, sktag);
362 		/* If EXPLICIT need length of surrounding tag */
363 		if (flags & ASN1_TFLG_EXPTAG)
364 			ret = ASN1_object_size(ndef, sklen, ttag);
365 		else ret = sklen;
366 
367 		if (!out)
368 			return ret;
369 
370 		/* Now encode this lot... */
371 		/* EXPLICIT tag */
372 		if (flags & ASN1_TFLG_EXPTAG)
373 			ASN1_put_object(out, ndef, sklen, ttag, tclass);
374 		/* SET or SEQUENCE and IMPLICIT tag */
375 		ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
376 		/* And the stuff itself */
377 		asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
378 								isset, iclass);
379 		if (ndef == 2)
380 			{
381 			ASN1_put_eoc(out);
382 			if (flags & ASN1_TFLG_EXPTAG)
383 				ASN1_put_eoc(out);
384 			}
385 
386 		return ret;
387 		}
388 
389 	if (flags & ASN1_TFLG_EXPTAG)
390 		{
391 		/* EXPLICIT tagging */
392 		/* Find length of tagged item */
393 		i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item),
394 								-1, iclass);
395 		if (!i)
396 			return 0;
397 		/* Find length of EXPLICIT tag */
398 		ret = ASN1_object_size(ndef, i, ttag);
399 		if (out)
400 			{
401 			/* Output tag and item */
402 			ASN1_put_object(out, ndef, i, ttag, tclass);
403 			ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
404 								-1, iclass);
405 			if (ndef == 2)
406 				ASN1_put_eoc(out);
407 			}
408 		return ret;
409 		}
410 
411 	/* Either normal or IMPLICIT tagging: combine class and flags */
412 	return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
413 						ttag, tclass | iclass);
414 
415 }
416 
417 /* Temporary structure used to hold DER encoding of items for SET OF */
418 
419 typedef	struct {
420 	unsigned char *data;
421 	int length;
422 	ASN1_VALUE *field;
423 } DER_ENC;
424 
der_cmp(const void * a,const void * b)425 static int der_cmp(const void *a, const void *b)
426 	{
427 	const DER_ENC *d1 = a, *d2 = b;
428 	int cmplen, i;
429 	cmplen = (d1->length < d2->length) ? d1->length : d2->length;
430 	i = memcmp(d1->data, d2->data, cmplen);
431 	if (i)
432 		return i;
433 	return d1->length - d2->length;
434 	}
435 
436 /* Output the content octets of SET OF or SEQUENCE OF */
437 
asn1_set_seq_out(STACK_OF (ASN1_VALUE)* sk,unsigned char ** out,int skcontlen,const ASN1_ITEM * item,int do_sort,int iclass)438 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
439 					int skcontlen, const ASN1_ITEM *item,
440 					int do_sort, int iclass)
441 	{
442 	size_t i;
443 	ASN1_VALUE *skitem;
444 	unsigned char *tmpdat = NULL, *p = NULL;
445 	DER_ENC *derlst = NULL, *tder;
446 	if (do_sort)
447 		 {
448 		/* Don't need to sort less than 2 items */
449 		if (sk_ASN1_VALUE_num(sk) < 2)
450 			do_sort = 0;
451 		else
452 			{
453 			derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk)
454 						* sizeof(*derlst));
455 			if (!derlst)
456 				return 0;
457 			tmpdat = OPENSSL_malloc(skcontlen);
458 			if (!tmpdat)
459 				{
460 				OPENSSL_free(derlst);
461 				return 0;
462 				}
463 			}
464 		}
465 	/* If not sorting just output each item */
466 	if (!do_sort)
467 		{
468 		for (i = 0; i < sk_ASN1_VALUE_num(sk); i++)
469 			{
470 			skitem = sk_ASN1_VALUE_value(sk, i);
471 			ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
472 			}
473 		return 1;
474 		}
475 	p = tmpdat;
476 
477 	/* Doing sort: build up a list of each member's DER encoding */
478 	for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
479 		{
480 		skitem = sk_ASN1_VALUE_value(sk, i);
481 		tder->data = p;
482 		tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
483 		tder->field = skitem;
484 		}
485 
486 	/* Now sort them */
487 	qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
488 	/* Output sorted DER encoding */
489 	p = *out;
490 	for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
491 		{
492 		memcpy(p, tder->data, tder->length);
493 		p += tder->length;
494 		}
495 	*out = p;
496 	/* If do_sort is 2 then reorder the STACK */
497 	if (do_sort == 2)
498 		{
499 		for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk);
500 							i++, tder++)
501 			(void)sk_ASN1_VALUE_set(sk, i, tder->field);
502 		}
503 	OPENSSL_free(derlst);
504 	OPENSSL_free(tmpdat);
505 	return 1;
506 	}
507 
asn1_i2d_ex_primitive(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_ITEM * it,int tag,int aclass)508 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
509 				const ASN1_ITEM *it, int tag, int aclass)
510 	{
511 	int len;
512 	int utype;
513 	int usetag;
514 	int ndef = 0;
515 
516 	utype = it->utype;
517 
518 	/* Get length of content octets and maybe find
519 	 * out the underlying type.
520 	 */
521 
522 	len = asn1_ex_i2c(pval, NULL, &utype, it);
523 
524 	/* If SEQUENCE, SET or OTHER then header is
525 	 * included in pseudo content octets so don't
526 	 * include tag+length. We need to check here
527 	 * because the call to asn1_ex_i2c() could change
528 	 * utype.
529 	 */
530 	if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
531 	   (utype == V_ASN1_OTHER))
532 		usetag = 0;
533 	else usetag = 1;
534 
535 	/* -1 means omit type */
536 
537 	if (len == -1)
538 		return 0;
539 
540 	/* -2 return is special meaning use ndef */
541 	if (len == -2)
542 		{
543 		ndef = 2;
544 		len = 0;
545 		}
546 
547 	/* If not implicitly tagged get tag from underlying type */
548 	if (tag == -1) tag = utype;
549 
550 	/* Output tag+length followed by content octets */
551 	if (out)
552 		{
553 		if (usetag)
554 			ASN1_put_object(out, ndef, len, tag, aclass);
555 		asn1_ex_i2c(pval, *out, &utype, it);
556 		if (ndef)
557 			ASN1_put_eoc(out);
558 		else
559 			*out += len;
560 		}
561 
562 	if (usetag)
563 		return ASN1_object_size(ndef, len, tag);
564 	return len;
565 	}
566 
567 /* Produce content octets from a structure */
568 
asn1_ex_i2c(ASN1_VALUE ** pval,unsigned char * cout,int * putype,const ASN1_ITEM * it)569 int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
570 				const ASN1_ITEM *it)
571 	{
572 	ASN1_BOOLEAN *tbool = NULL;
573 	ASN1_STRING *strtmp;
574 	ASN1_OBJECT *otmp;
575 	int utype;
576 	const unsigned char *cont;
577 	unsigned char c;
578 	int len;
579 	const ASN1_PRIMITIVE_FUNCS *pf;
580 	pf = it->funcs;
581 	if (pf && pf->prim_i2c)
582 		return pf->prim_i2c(pval, cout, putype, it);
583 
584 	/* Should type be omitted? */
585 	if ((it->itype != ASN1_ITYPE_PRIMITIVE)
586 		|| (it->utype != V_ASN1_BOOLEAN))
587 		{
588 		if (!*pval) return -1;
589 		}
590 
591 	if (it->itype == ASN1_ITYPE_MSTRING)
592 		{
593 		/* If MSTRING type set the underlying type */
594 		strtmp = (ASN1_STRING *)*pval;
595 		utype = strtmp->type;
596 		*putype = utype;
597 		}
598 	else if (it->utype == V_ASN1_ANY)
599 		{
600 		/* If ANY set type and pointer to value */
601 		ASN1_TYPE *typ;
602 		typ = (ASN1_TYPE *)*pval;
603 		utype = typ->type;
604 		*putype = utype;
605 		pval = &typ->value.asn1_value;
606 		}
607 	else utype = *putype;
608 
609 	switch(utype)
610 		{
611 		case V_ASN1_OBJECT:
612 		otmp = (ASN1_OBJECT *)*pval;
613 		cont = otmp->data;
614 		len = otmp->length;
615 		break;
616 
617 		case V_ASN1_NULL:
618 		cont = NULL;
619 		len = 0;
620 		break;
621 
622 		case V_ASN1_BOOLEAN:
623 		tbool = (ASN1_BOOLEAN *)pval;
624 		if (*tbool == -1)
625 			return -1;
626 		if (it->utype != V_ASN1_ANY)
627 			{
628 			/* Default handling if value == size field then omit */
629 			if (*tbool && (it->size > 0))
630 				return -1;
631 			if (!*tbool && !it->size)
632 				return -1;
633 			}
634 		c = (unsigned char)*tbool;
635 		cont = &c;
636 		len = 1;
637 		break;
638 
639 		case V_ASN1_BIT_STRING:
640 		return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval,
641 							cout ? &cout : NULL);
642 		break;
643 
644 		case V_ASN1_INTEGER:
645 		case V_ASN1_NEG_INTEGER:
646 		case V_ASN1_ENUMERATED:
647 		case V_ASN1_NEG_ENUMERATED:
648 		/* These are all have the same content format
649 		 * as ASN1_INTEGER
650 		 */
651 		return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval,
652 							cout ? &cout : NULL);
653 		break;
654 
655 		case V_ASN1_OCTET_STRING:
656 		case V_ASN1_NUMERICSTRING:
657 		case V_ASN1_PRINTABLESTRING:
658 		case V_ASN1_T61STRING:
659 		case V_ASN1_VIDEOTEXSTRING:
660 		case V_ASN1_IA5STRING:
661 		case V_ASN1_UTCTIME:
662 		case V_ASN1_GENERALIZEDTIME:
663 		case V_ASN1_GRAPHICSTRING:
664 		case V_ASN1_VISIBLESTRING:
665 		case V_ASN1_GENERALSTRING:
666 		case V_ASN1_UNIVERSALSTRING:
667 		case V_ASN1_BMPSTRING:
668 		case V_ASN1_UTF8STRING:
669 		case V_ASN1_SEQUENCE:
670 		case V_ASN1_SET:
671 		default:
672 		/* All based on ASN1_STRING and handled the same */
673 		strtmp = (ASN1_STRING *)*pval;
674 		/* Special handling for NDEF */
675 		if ((it->size == ASN1_TFLG_NDEF)
676 			&& (strtmp->flags & ASN1_STRING_FLAG_NDEF))
677 			{
678 			if (cout)
679 				{
680 				strtmp->data = cout;
681 				strtmp->length = 0;
682 				}
683 			/* Special return code */
684 			return -2;
685 			}
686 		cont = strtmp->data;
687 		len = strtmp->length;
688 
689 		break;
690 
691 		}
692 	if (cout && len)
693 		memcpy(cout, cont, len);
694 	return len;
695 	}
696