xref: /onnv-gate/usr/src/common/openssl/crypto/asn1/tasn_dec.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /* tasn_dec.c */
2*0Sstevel@tonic-gate /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3*0Sstevel@tonic-gate  * project 2000.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate /* ====================================================================
6*0Sstevel@tonic-gate  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
9*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
10*0Sstevel@tonic-gate  * are met:
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
13*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
16*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
17*0Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
18*0Sstevel@tonic-gate  *    distribution.
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
21*0Sstevel@tonic-gate  *    software must display the following acknowledgment:
22*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
23*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26*0Sstevel@tonic-gate  *    endorse or promote products derived from this software without
27*0Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
28*0Sstevel@tonic-gate  *    licensing@OpenSSL.org.
29*0Sstevel@tonic-gate  *
30*0Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
31*0Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
32*0Sstevel@tonic-gate  *    permission of the OpenSSL Project.
33*0Sstevel@tonic-gate  *
34*0Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
35*0Sstevel@tonic-gate  *    acknowledgment:
36*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
37*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40*0Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42*0Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43*0Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44*0Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46*0Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48*0Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49*0Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50*0Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
51*0Sstevel@tonic-gate  * ====================================================================
52*0Sstevel@tonic-gate  *
53*0Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
54*0Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
55*0Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include <stddef.h>
61*0Sstevel@tonic-gate #include <string.h>
62*0Sstevel@tonic-gate #include <openssl/asn1.h>
63*0Sstevel@tonic-gate #include <openssl/asn1t.h>
64*0Sstevel@tonic-gate #include <openssl/objects.h>
65*0Sstevel@tonic-gate #include <openssl/buffer.h>
66*0Sstevel@tonic-gate #include <openssl/err.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static int asn1_check_eoc(unsigned char **in, long len);
69*0Sstevel@tonic-gate static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass);
70*0Sstevel@tonic-gate static int collect_data(BUF_MEM *buf, unsigned char **p, long plen);
71*0Sstevel@tonic-gate static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst,
72*0Sstevel@tonic-gate 			unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx);
73*0Sstevel@tonic-gate static int asn1_template_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
74*0Sstevel@tonic-gate static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx);
75*0Sstevel@tonic-gate static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long len,
76*0Sstevel@tonic-gate 					const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /* Table to convert tags to bit values, used for MSTRING type */
79*0Sstevel@tonic-gate static unsigned long tag2bit[32]={
80*0Sstevel@tonic-gate 0,	0,	0,	B_ASN1_BIT_STRING,	/* tags  0 -  3 */
81*0Sstevel@tonic-gate B_ASN1_OCTET_STRING,	0,	0,		B_ASN1_UNKNOWN,/* tags  4- 7 */
82*0Sstevel@tonic-gate B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,	B_ASN1_UNKNOWN,/* tags  8-11 */
83*0Sstevel@tonic-gate B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */
84*0Sstevel@tonic-gate 0,	0,	B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING,   /* tags 16-19 */
85*0Sstevel@tonic-gate B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING,       /* tags 20-22 */
86*0Sstevel@tonic-gate B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME,			       /* tags 23-24 */
87*0Sstevel@tonic-gate B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING,  /* tags 25-27 */
88*0Sstevel@tonic-gate B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */
89*0Sstevel@tonic-gate 	};
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate unsigned long ASN1_tag2bit(int tag)
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	if((tag < 0) || (tag > 30)) return 0;
94*0Sstevel@tonic-gate 	return tag2bit[tag];
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /* Macro to initialize and invalidate the cache */
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate #define asn1_tlc_clear(c)	if(c) (c)->valid = 0
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /* Decode an ASN1 item, this currently behaves just
102*0Sstevel@tonic-gate  * like a standard 'd2i' function. 'in' points to
103*0Sstevel@tonic-gate  * a buffer to read the data from, in future we will
104*0Sstevel@tonic-gate  * have more advanced versions that can input data
105*0Sstevel@tonic-gate  * a piece at a time and this will simply be a special
106*0Sstevel@tonic-gate  * case.
107*0Sstevel@tonic-gate  */
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it)
110*0Sstevel@tonic-gate {
111*0Sstevel@tonic-gate 	ASN1_TLC c;
112*0Sstevel@tonic-gate 	ASN1_VALUE *ptmpval = NULL;
113*0Sstevel@tonic-gate 	if(!pval) pval = &ptmpval;
114*0Sstevel@tonic-gate 	asn1_tlc_clear(&c);
115*0Sstevel@tonic-gate 	if(ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0)
116*0Sstevel@tonic-gate 		return *pval;
117*0Sstevel@tonic-gate 	return NULL;
118*0Sstevel@tonic-gate }
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate int ASN1_template_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_TEMPLATE *tt)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	ASN1_TLC c;
123*0Sstevel@tonic-gate 	asn1_tlc_clear(&c);
124*0Sstevel@tonic-gate 	return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate /* Decode an item, taking care of IMPLICIT tagging, if any.
129*0Sstevel@tonic-gate  * If 'opt' set and tag mismatch return -1 to handle OPTIONAL
130*0Sstevel@tonic-gate  */
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it,
133*0Sstevel@tonic-gate 				int tag, int aclass, char opt, ASN1_TLC *ctx)
134*0Sstevel@tonic-gate {
135*0Sstevel@tonic-gate 	const ASN1_TEMPLATE *tt, *errtt = NULL;
136*0Sstevel@tonic-gate 	const ASN1_COMPAT_FUNCS *cf;
137*0Sstevel@tonic-gate 	const ASN1_EXTERN_FUNCS *ef;
138*0Sstevel@tonic-gate 	const ASN1_AUX *aux = it->funcs;
139*0Sstevel@tonic-gate 	ASN1_aux_cb *asn1_cb;
140*0Sstevel@tonic-gate 	unsigned char *p, *q, imphack = 0, oclass;
141*0Sstevel@tonic-gate 	char seq_eoc, seq_nolen, cst, isopt;
142*0Sstevel@tonic-gate 	long tmplen;
143*0Sstevel@tonic-gate 	int i;
144*0Sstevel@tonic-gate 	int otag;
145*0Sstevel@tonic-gate 	int ret = 0;
146*0Sstevel@tonic-gate 	ASN1_VALUE *pchval, **pchptr, *ptmpval;
147*0Sstevel@tonic-gate 	if(!pval) return 0;
148*0Sstevel@tonic-gate 	if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb;
149*0Sstevel@tonic-gate 	else asn1_cb = 0;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	switch(it->itype) {
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 		case ASN1_ITYPE_PRIMITIVE:
154*0Sstevel@tonic-gate 		if(it->templates) {
155*0Sstevel@tonic-gate 			/* tagging or OPTIONAL is currently illegal on an item template
156*0Sstevel@tonic-gate 			 * because the flags can't get passed down. In practice this isn't
157*0Sstevel@tonic-gate 			 * a problem: we include the relevant flags from the item template
158*0Sstevel@tonic-gate 			 * in the template itself.
159*0Sstevel@tonic-gate 			 */
160*0Sstevel@tonic-gate 			if ((tag != -1) || opt) {
161*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
162*0Sstevel@tonic-gate 				goto err;
163*0Sstevel@tonic-gate 			}
164*0Sstevel@tonic-gate 			return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx);
165*0Sstevel@tonic-gate 		}
166*0Sstevel@tonic-gate 		return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx);
167*0Sstevel@tonic-gate 		break;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 		case ASN1_ITYPE_MSTRING:
170*0Sstevel@tonic-gate 		p = *in;
171*0Sstevel@tonic-gate 		/* Just read in tag and class */
172*0Sstevel@tonic-gate 		ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, &p, len, -1, 0, 1, ctx);
173*0Sstevel@tonic-gate 		if(!ret) {
174*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
175*0Sstevel@tonic-gate 			goto err;
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate 		/* Must be UNIVERSAL class */
178*0Sstevel@tonic-gate 		if(oclass != V_ASN1_UNIVERSAL) {
179*0Sstevel@tonic-gate 			/* If OPTIONAL, assume this is OK */
180*0Sstevel@tonic-gate 			if(opt) return -1;
181*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL);
182*0Sstevel@tonic-gate 			goto err;
183*0Sstevel@tonic-gate 		}
184*0Sstevel@tonic-gate 		/* Check tag matches bit map */
185*0Sstevel@tonic-gate 		if(!(ASN1_tag2bit(otag) & it->utype)) {
186*0Sstevel@tonic-gate 			/* If OPTIONAL, assume this is OK */
187*0Sstevel@tonic-gate 			if(opt) return -1;
188*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG);
189*0Sstevel@tonic-gate 			goto err;
190*0Sstevel@tonic-gate 		}
191*0Sstevel@tonic-gate 		return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 		case ASN1_ITYPE_EXTERN:
194*0Sstevel@tonic-gate 		/* Use new style d2i */
195*0Sstevel@tonic-gate 		ef = it->funcs;
196*0Sstevel@tonic-gate 		return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx);
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 		case ASN1_ITYPE_COMPAT:
199*0Sstevel@tonic-gate 		/* we must resort to old style evil hackery */
200*0Sstevel@tonic-gate 		cf = it->funcs;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 		/* If OPTIONAL see if it is there */
203*0Sstevel@tonic-gate 		if(opt) {
204*0Sstevel@tonic-gate 			int exptag;
205*0Sstevel@tonic-gate 			p = *in;
206*0Sstevel@tonic-gate 			if(tag == -1) exptag = it->utype;
207*0Sstevel@tonic-gate 			else exptag = tag;
208*0Sstevel@tonic-gate 			/* Don't care about anything other than presence of expected tag */
209*0Sstevel@tonic-gate 			ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, &p, len, exptag, aclass, 1, ctx);
210*0Sstevel@tonic-gate 			if(!ret) {
211*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
212*0Sstevel@tonic-gate 				goto err;
213*0Sstevel@tonic-gate 			}
214*0Sstevel@tonic-gate 			if(ret == -1) return -1;
215*0Sstevel@tonic-gate 		}
216*0Sstevel@tonic-gate 		/* This is the old style evil hack IMPLICIT handling:
217*0Sstevel@tonic-gate 		 * since the underlying code is expecting a tag and
218*0Sstevel@tonic-gate 		 * class other than the one present we change the
219*0Sstevel@tonic-gate 		 * buffer temporarily then change it back afterwards.
220*0Sstevel@tonic-gate 		 * This doesn't and never did work for tags > 30.
221*0Sstevel@tonic-gate 		 *
222*0Sstevel@tonic-gate 		 * Yes this is *horrible* but it is only needed for
223*0Sstevel@tonic-gate 		 * old style d2i which will hopefully not be around
224*0Sstevel@tonic-gate 		 * for much longer.
225*0Sstevel@tonic-gate 		 * FIXME: should copy the buffer then modify it so
226*0Sstevel@tonic-gate 		 * the input buffer can be const: we should *always*
227*0Sstevel@tonic-gate 		 * copy because the old style d2i might modify the
228*0Sstevel@tonic-gate 		 * buffer.
229*0Sstevel@tonic-gate 		 */
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		if(tag != -1) {
232*0Sstevel@tonic-gate 			p = *in;
233*0Sstevel@tonic-gate 			imphack = *p;
234*0Sstevel@tonic-gate 			*p = (unsigned char)((*p & V_ASN1_CONSTRUCTED) | it->utype);
235*0Sstevel@tonic-gate 		}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 		ptmpval = cf->asn1_d2i(pval, in, len);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 		if(tag != -1) *p = imphack;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 		if(ptmpval) return 1;
242*0Sstevel@tonic-gate 		ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
243*0Sstevel@tonic-gate 		goto err;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 		case ASN1_ITYPE_CHOICE:
247*0Sstevel@tonic-gate 		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))
248*0Sstevel@tonic-gate 				goto auxerr;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		/* Allocate structure */
251*0Sstevel@tonic-gate 		if(!*pval) {
252*0Sstevel@tonic-gate 			if(!ASN1_item_ex_new(pval, it)) {
253*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
254*0Sstevel@tonic-gate 				goto err;
255*0Sstevel@tonic-gate 			}
256*0Sstevel@tonic-gate 		}
257*0Sstevel@tonic-gate 		/* CHOICE type, try each possibility in turn */
258*0Sstevel@tonic-gate 		pchval = NULL;
259*0Sstevel@tonic-gate 		p = *in;
260*0Sstevel@tonic-gate 		for(i = 0, tt=it->templates; i < it->tcount; i++, tt++) {
261*0Sstevel@tonic-gate 			pchptr = asn1_get_field_ptr(pval, tt);
262*0Sstevel@tonic-gate 			/* We mark field as OPTIONAL so its absence
263*0Sstevel@tonic-gate 			 * can be recognised.
264*0Sstevel@tonic-gate 			 */
265*0Sstevel@tonic-gate 			ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
266*0Sstevel@tonic-gate 			/* If field not present, try the next one */
267*0Sstevel@tonic-gate 			if(ret == -1) continue;
268*0Sstevel@tonic-gate 			/* If positive return, read OK, break loop */
269*0Sstevel@tonic-gate 			if(ret > 0) break;
270*0Sstevel@tonic-gate 			/* Otherwise must be an ASN1 parsing error */
271*0Sstevel@tonic-gate 			errtt = tt;
272*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
273*0Sstevel@tonic-gate 			goto err;
274*0Sstevel@tonic-gate 		}
275*0Sstevel@tonic-gate 		/* Did we fall off the end without reading anything? */
276*0Sstevel@tonic-gate 		if(i == it->tcount) {
277*0Sstevel@tonic-gate 			/* If OPTIONAL, this is OK */
278*0Sstevel@tonic-gate 			if(opt) {
279*0Sstevel@tonic-gate 				/* Free and zero it */
280*0Sstevel@tonic-gate 				ASN1_item_ex_free(pval, it);
281*0Sstevel@tonic-gate 				return -1;
282*0Sstevel@tonic-gate 			}
283*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);
284*0Sstevel@tonic-gate 			goto err;
285*0Sstevel@tonic-gate 		}
286*0Sstevel@tonic-gate 		asn1_set_choice_selector(pval, i, it);
287*0Sstevel@tonic-gate 		*in = p;
288*0Sstevel@tonic-gate 		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))
289*0Sstevel@tonic-gate 				goto auxerr;
290*0Sstevel@tonic-gate 		return 1;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		case ASN1_ITYPE_SEQUENCE:
293*0Sstevel@tonic-gate 		p = *in;
294*0Sstevel@tonic-gate 		tmplen = len;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 		/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
297*0Sstevel@tonic-gate 		if(tag == -1) {
298*0Sstevel@tonic-gate 			tag = V_ASN1_SEQUENCE;
299*0Sstevel@tonic-gate 			aclass = V_ASN1_UNIVERSAL;
300*0Sstevel@tonic-gate 		}
301*0Sstevel@tonic-gate 		/* Get SEQUENCE length and update len, p */
302*0Sstevel@tonic-gate 		ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, &p, len, tag, aclass, opt, ctx);
303*0Sstevel@tonic-gate 		if(!ret) {
304*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
305*0Sstevel@tonic-gate 			goto err;
306*0Sstevel@tonic-gate 		} else if(ret == -1) return -1;
307*0Sstevel@tonic-gate 		if(aux && (aux->flags & ASN1_AFLG_BROKEN)) {
308*0Sstevel@tonic-gate 			len = tmplen - (p - *in);
309*0Sstevel@tonic-gate 			seq_nolen = 1;
310*0Sstevel@tonic-gate 		} else seq_nolen = seq_eoc;	/* If indefinite we don't do a length check */
311*0Sstevel@tonic-gate 		if(!cst) {
312*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
313*0Sstevel@tonic-gate 			goto err;
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		if(!*pval) {
317*0Sstevel@tonic-gate 			if(!ASN1_item_ex_new(pval, it)) {
318*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
319*0Sstevel@tonic-gate 				goto err;
320*0Sstevel@tonic-gate 			}
321*0Sstevel@tonic-gate 		}
322*0Sstevel@tonic-gate 		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))
323*0Sstevel@tonic-gate 				goto auxerr;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 		/* Get each field entry */
326*0Sstevel@tonic-gate 		for(i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
327*0Sstevel@tonic-gate 			const ASN1_TEMPLATE *seqtt;
328*0Sstevel@tonic-gate 			ASN1_VALUE **pseqval;
329*0Sstevel@tonic-gate 			seqtt = asn1_do_adb(pval, tt, 1);
330*0Sstevel@tonic-gate 			if(!seqtt) goto err;
331*0Sstevel@tonic-gate 			pseqval = asn1_get_field_ptr(pval, seqtt);
332*0Sstevel@tonic-gate 			/* Have we ran out of data? */
333*0Sstevel@tonic-gate 			if(!len) break;
334*0Sstevel@tonic-gate 			q = p;
335*0Sstevel@tonic-gate 			if(asn1_check_eoc(&p, len)) {
336*0Sstevel@tonic-gate 				if(!seq_eoc) {
337*0Sstevel@tonic-gate 					ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC);
338*0Sstevel@tonic-gate 					goto err;
339*0Sstevel@tonic-gate 				}
340*0Sstevel@tonic-gate 				len -= p - q;
341*0Sstevel@tonic-gate 				seq_eoc = 0;
342*0Sstevel@tonic-gate 				q = p;
343*0Sstevel@tonic-gate 				break;
344*0Sstevel@tonic-gate 			}
345*0Sstevel@tonic-gate 			/* This determines the OPTIONAL flag value. The field cannot
346*0Sstevel@tonic-gate 			 * be omitted if it is the last of a SEQUENCE and there is
347*0Sstevel@tonic-gate 			 * still data to be read. This isn't strictly necessary but
348*0Sstevel@tonic-gate 			 * it increases efficiency in some cases.
349*0Sstevel@tonic-gate 			 */
350*0Sstevel@tonic-gate 			if(i == (it->tcount - 1)) isopt = 0;
351*0Sstevel@tonic-gate 			else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
352*0Sstevel@tonic-gate 			/* attempt to read in field, allowing each to be OPTIONAL */
353*0Sstevel@tonic-gate 			ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
354*0Sstevel@tonic-gate 			if(!ret) {
355*0Sstevel@tonic-gate 				errtt = seqtt;
356*0Sstevel@tonic-gate 				goto err;
357*0Sstevel@tonic-gate 			} else if(ret == -1) {
358*0Sstevel@tonic-gate 				/* OPTIONAL component absent. Free and zero the field
359*0Sstevel@tonic-gate 				 */
360*0Sstevel@tonic-gate 				ASN1_template_free(pseqval, seqtt);
361*0Sstevel@tonic-gate 				continue;
362*0Sstevel@tonic-gate 			}
363*0Sstevel@tonic-gate 			/* Update length */
364*0Sstevel@tonic-gate 			len -= p - q;
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 		/* Check for EOC if expecting one */
367*0Sstevel@tonic-gate 		if(seq_eoc && !asn1_check_eoc(&p, len)) {
368*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC);
369*0Sstevel@tonic-gate 			goto err;
370*0Sstevel@tonic-gate 		}
371*0Sstevel@tonic-gate 		/* Check all data read */
372*0Sstevel@tonic-gate 		if(!seq_nolen && len) {
373*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH);
374*0Sstevel@tonic-gate 			goto err;
375*0Sstevel@tonic-gate 		}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		/* If we get here we've got no more data in the SEQUENCE,
378*0Sstevel@tonic-gate 		 * however we may not have read all fields so check all
379*0Sstevel@tonic-gate 		 * remaining are OPTIONAL and clear any that are.
380*0Sstevel@tonic-gate 		 */
381*0Sstevel@tonic-gate 		for(; i < it->tcount; tt++, i++) {
382*0Sstevel@tonic-gate 			const ASN1_TEMPLATE *seqtt;
383*0Sstevel@tonic-gate 			seqtt = asn1_do_adb(pval, tt, 1);
384*0Sstevel@tonic-gate 			if(!seqtt) goto err;
385*0Sstevel@tonic-gate 			if(seqtt->flags & ASN1_TFLG_OPTIONAL) {
386*0Sstevel@tonic-gate 				ASN1_VALUE **pseqval;
387*0Sstevel@tonic-gate 				pseqval = asn1_get_field_ptr(pval, seqtt);
388*0Sstevel@tonic-gate 				ASN1_template_free(pseqval, seqtt);
389*0Sstevel@tonic-gate 			} else {
390*0Sstevel@tonic-gate 				errtt = seqtt;
391*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING);
392*0Sstevel@tonic-gate 				goto err;
393*0Sstevel@tonic-gate 			}
394*0Sstevel@tonic-gate 		}
395*0Sstevel@tonic-gate 		/* Save encoding */
396*0Sstevel@tonic-gate 		if(!asn1_enc_save(pval, *in, p - *in, it)) goto auxerr;
397*0Sstevel@tonic-gate 		*in = p;
398*0Sstevel@tonic-gate 		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))
399*0Sstevel@tonic-gate 				goto auxerr;
400*0Sstevel@tonic-gate 		return 1;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 		default:
403*0Sstevel@tonic-gate 		return 0;
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 	auxerr:
406*0Sstevel@tonic-gate 	ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR);
407*0Sstevel@tonic-gate 	err:
408*0Sstevel@tonic-gate 	ASN1_item_ex_free(pval, it);
409*0Sstevel@tonic-gate 	if(errtt) ERR_add_error_data(4, "Field=", errtt->field_name, ", Type=", it->sname);
410*0Sstevel@tonic-gate 	else ERR_add_error_data(2, "Type=", it->sname);
411*0Sstevel@tonic-gate 	return 0;
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /* Templates are handled with two separate functions. One handles any EXPLICIT tag and the other handles the
415*0Sstevel@tonic-gate  * rest.
416*0Sstevel@tonic-gate  */
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate static int asn1_template_ex_d2i(ASN1_VALUE **val, unsigned char **in, long inlen, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
419*0Sstevel@tonic-gate {
420*0Sstevel@tonic-gate 	int flags, aclass;
421*0Sstevel@tonic-gate 	int ret;
422*0Sstevel@tonic-gate 	long len;
423*0Sstevel@tonic-gate 	unsigned char *p, *q;
424*0Sstevel@tonic-gate 	char exp_eoc;
425*0Sstevel@tonic-gate 	if(!val) return 0;
426*0Sstevel@tonic-gate 	flags = tt->flags;
427*0Sstevel@tonic-gate 	aclass = flags & ASN1_TFLG_TAG_CLASS;
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	p = *in;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/* Check if EXPLICIT tag expected */
432*0Sstevel@tonic-gate 	if(flags & ASN1_TFLG_EXPTAG) {
433*0Sstevel@tonic-gate 		char cst;
434*0Sstevel@tonic-gate 		/* Need to work out amount of data available to the inner content and where it
435*0Sstevel@tonic-gate 		 * starts: so read in EXPLICIT header to get the info.
436*0Sstevel@tonic-gate 		 */
437*0Sstevel@tonic-gate 		ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, &p, inlen, tt->tag, aclass, opt, ctx);
438*0Sstevel@tonic-gate 		q = p;
439*0Sstevel@tonic-gate 		if(!ret) {
440*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
441*0Sstevel@tonic-gate 			return 0;
442*0Sstevel@tonic-gate 		} else if(ret == -1) return -1;
443*0Sstevel@tonic-gate 		if(!cst) {
444*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED);
445*0Sstevel@tonic-gate 			return 0;
446*0Sstevel@tonic-gate 		}
447*0Sstevel@tonic-gate 		/* We've found the field so it can't be OPTIONAL now */
448*0Sstevel@tonic-gate 		ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
449*0Sstevel@tonic-gate 		if(!ret) {
450*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
451*0Sstevel@tonic-gate 			return 0;
452*0Sstevel@tonic-gate 		}
453*0Sstevel@tonic-gate 		/* We read the field in OK so update length */
454*0Sstevel@tonic-gate 		len -= p - q;
455*0Sstevel@tonic-gate 		if(exp_eoc) {
456*0Sstevel@tonic-gate 			/* If NDEF we must have an EOC here */
457*0Sstevel@tonic-gate 			if(!asn1_check_eoc(&p, len)) {
458*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_MISSING_EOC);
459*0Sstevel@tonic-gate 				goto err;
460*0Sstevel@tonic-gate 			}
461*0Sstevel@tonic-gate 		} else {
462*0Sstevel@tonic-gate 			/* Otherwise we must hit the EXPLICIT tag end or its an error */
463*0Sstevel@tonic-gate 			if(len) {
464*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_EXPLICIT_LENGTH_MISMATCH);
465*0Sstevel@tonic-gate 				goto err;
466*0Sstevel@tonic-gate 			}
467*0Sstevel@tonic-gate 		}
468*0Sstevel@tonic-gate 	} else
469*0Sstevel@tonic-gate 		return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	*in = p;
472*0Sstevel@tonic-gate 	return 1;
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	err:
475*0Sstevel@tonic-gate 	ASN1_template_free(val, tt);
476*0Sstevel@tonic-gate 	*val = NULL;
477*0Sstevel@tonic-gate 	return 0;
478*0Sstevel@tonic-gate }
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate static int asn1_template_noexp_d2i(ASN1_VALUE **val, unsigned char **in, long len, const ASN1_TEMPLATE *tt, char opt, ASN1_TLC *ctx)
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	int flags, aclass;
483*0Sstevel@tonic-gate 	int ret;
484*0Sstevel@tonic-gate 	unsigned char *p, *q;
485*0Sstevel@tonic-gate 	if(!val) return 0;
486*0Sstevel@tonic-gate 	flags = tt->flags;
487*0Sstevel@tonic-gate 	aclass = flags & ASN1_TFLG_TAG_CLASS;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	p = *in;
490*0Sstevel@tonic-gate 	q = p;
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	if(flags & ASN1_TFLG_SK_MASK) {
493*0Sstevel@tonic-gate 		/* SET OF, SEQUENCE OF */
494*0Sstevel@tonic-gate 		int sktag, skaclass;
495*0Sstevel@tonic-gate 		char sk_eoc;
496*0Sstevel@tonic-gate 		/* First work out expected inner tag value */
497*0Sstevel@tonic-gate 		if(flags & ASN1_TFLG_IMPTAG) {
498*0Sstevel@tonic-gate 			sktag = tt->tag;
499*0Sstevel@tonic-gate 			skaclass = aclass;
500*0Sstevel@tonic-gate 		} else {
501*0Sstevel@tonic-gate 			skaclass = V_ASN1_UNIVERSAL;
502*0Sstevel@tonic-gate 			if(flags & ASN1_TFLG_SET_OF) sktag = V_ASN1_SET;
503*0Sstevel@tonic-gate 			else sktag = V_ASN1_SEQUENCE;
504*0Sstevel@tonic-gate 		}
505*0Sstevel@tonic-gate 		/* Get the tag */
506*0Sstevel@tonic-gate 		ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, &p, len, sktag, skaclass, opt, ctx);
507*0Sstevel@tonic-gate 		if(!ret) {
508*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_NESTED_ASN1_ERROR);
509*0Sstevel@tonic-gate 			return 0;
510*0Sstevel@tonic-gate 		} else if(ret == -1) return -1;
511*0Sstevel@tonic-gate 		if(!*val) *val = (ASN1_VALUE *)sk_new_null();
512*0Sstevel@tonic-gate 		else {
513*0Sstevel@tonic-gate 			/* We've got a valid STACK: free up any items present */
514*0Sstevel@tonic-gate 			STACK *sktmp = (STACK *)*val;
515*0Sstevel@tonic-gate 			ASN1_VALUE *vtmp;
516*0Sstevel@tonic-gate 			while(sk_num(sktmp) > 0) {
517*0Sstevel@tonic-gate 				vtmp = (ASN1_VALUE *)sk_pop(sktmp);
518*0Sstevel@tonic-gate 				ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item));
519*0Sstevel@tonic-gate 			}
520*0Sstevel@tonic-gate 		}
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 		if(!*val) {
523*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_MALLOC_FAILURE);
524*0Sstevel@tonic-gate 			goto err;
525*0Sstevel@tonic-gate 		}
526*0Sstevel@tonic-gate 		/* Read as many items as we can */
527*0Sstevel@tonic-gate 		while(len > 0) {
528*0Sstevel@tonic-gate 			ASN1_VALUE *skfield;
529*0Sstevel@tonic-gate 			q = p;
530*0Sstevel@tonic-gate 			/* See if EOC found */
531*0Sstevel@tonic-gate 			if(asn1_check_eoc(&p, len)) {
532*0Sstevel@tonic-gate 				if(!sk_eoc) {
533*0Sstevel@tonic-gate 					ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_UNEXPECTED_EOC);
534*0Sstevel@tonic-gate 					goto err;
535*0Sstevel@tonic-gate 				}
536*0Sstevel@tonic-gate 				len -= p - q;
537*0Sstevel@tonic-gate 				sk_eoc = 0;
538*0Sstevel@tonic-gate 				break;
539*0Sstevel@tonic-gate 			}
540*0Sstevel@tonic-gate 			skfield = NULL;
541*0Sstevel@tonic-gate 			if(!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
542*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
543*0Sstevel@tonic-gate 				goto err;
544*0Sstevel@tonic-gate 			}
545*0Sstevel@tonic-gate 			len -= p - q;
546*0Sstevel@tonic-gate 			if(!sk_push((STACK *)*val, (char *)skfield)) {
547*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_MALLOC_FAILURE);
548*0Sstevel@tonic-gate 				goto err;
549*0Sstevel@tonic-gate 			}
550*0Sstevel@tonic-gate 		}
551*0Sstevel@tonic-gate 		if(sk_eoc) {
552*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_MISSING_EOC);
553*0Sstevel@tonic-gate 			goto err;
554*0Sstevel@tonic-gate 		}
555*0Sstevel@tonic-gate 	} else if(flags & ASN1_TFLG_IMPTAG) {
556*0Sstevel@tonic-gate 		/* IMPLICIT tagging */
557*0Sstevel@tonic-gate 		ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
558*0Sstevel@tonic-gate 		if(!ret) {
559*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
560*0Sstevel@tonic-gate 			goto err;
561*0Sstevel@tonic-gate 		} else if(ret == -1) return -1;
562*0Sstevel@tonic-gate 	} else {
563*0Sstevel@tonic-gate 		/* Nothing special */
564*0Sstevel@tonic-gate 		ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx);
565*0Sstevel@tonic-gate 		if(!ret) {
566*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR);
567*0Sstevel@tonic-gate 			goto err;
568*0Sstevel@tonic-gate 		} else if(ret == -1) return -1;
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	*in = p;
572*0Sstevel@tonic-gate 	return 1;
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	err:
575*0Sstevel@tonic-gate 	ASN1_template_free(val, tt);
576*0Sstevel@tonic-gate 	*val = NULL;
577*0Sstevel@tonic-gate 	return 0;
578*0Sstevel@tonic-gate }
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inlen,
581*0Sstevel@tonic-gate 						const ASN1_ITEM *it,
582*0Sstevel@tonic-gate 						int tag, int aclass, char opt, ASN1_TLC *ctx)
583*0Sstevel@tonic-gate {
584*0Sstevel@tonic-gate 	int ret = 0, utype;
585*0Sstevel@tonic-gate 	long plen;
586*0Sstevel@tonic-gate 	char cst, inf, free_cont = 0;
587*0Sstevel@tonic-gate 	unsigned char *p;
588*0Sstevel@tonic-gate 	BUF_MEM buf;
589*0Sstevel@tonic-gate 	unsigned char *cont = NULL;
590*0Sstevel@tonic-gate 	long len;
591*0Sstevel@tonic-gate 	if(!pval) {
592*0Sstevel@tonic-gate 		ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL);
593*0Sstevel@tonic-gate 		return 0; /* Should never happen */
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	if(it->itype == ASN1_ITYPE_MSTRING) {
597*0Sstevel@tonic-gate 		utype = tag;
598*0Sstevel@tonic-gate 		tag = -1;
599*0Sstevel@tonic-gate 	} else utype = it->utype;
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	if(utype == V_ASN1_ANY) {
602*0Sstevel@tonic-gate 		/* If type is ANY need to figure out type from tag */
603*0Sstevel@tonic-gate 		unsigned char oclass;
604*0Sstevel@tonic-gate 		if(tag >= 0) {
605*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY);
606*0Sstevel@tonic-gate 			return 0;
607*0Sstevel@tonic-gate 		}
608*0Sstevel@tonic-gate 		if(opt) {
609*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_OPTIONAL_ANY);
610*0Sstevel@tonic-gate 			return 0;
611*0Sstevel@tonic-gate 		}
612*0Sstevel@tonic-gate 		p = *in;
613*0Sstevel@tonic-gate 		ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, &p, inlen, -1, 0, 0, ctx);
614*0Sstevel@tonic-gate 		if(!ret) {
615*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
616*0Sstevel@tonic-gate 			return 0;
617*0Sstevel@tonic-gate 		}
618*0Sstevel@tonic-gate 		if(oclass != V_ASN1_UNIVERSAL) utype = V_ASN1_OTHER;
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 	if(tag == -1) {
621*0Sstevel@tonic-gate 		tag = utype;
622*0Sstevel@tonic-gate 		aclass = V_ASN1_UNIVERSAL;
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 	p = *in;
625*0Sstevel@tonic-gate 	/* Check header */
626*0Sstevel@tonic-gate 	ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, aclass, opt, ctx);
627*0Sstevel@tonic-gate 	if(!ret) {
628*0Sstevel@tonic-gate 		ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR);
629*0Sstevel@tonic-gate 		return 0;
630*0Sstevel@tonic-gate 	} else if(ret == -1) return -1;
631*0Sstevel@tonic-gate 	/* SEQUENCE, SET and "OTHER" are left in encoded form */
632*0Sstevel@tonic-gate 	if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) {
633*0Sstevel@tonic-gate 		/* Clear context cache for type OTHER because the auto clear when
634*0Sstevel@tonic-gate 		 * we have a exact match wont work
635*0Sstevel@tonic-gate 		 */
636*0Sstevel@tonic-gate 		if(utype == V_ASN1_OTHER) {
637*0Sstevel@tonic-gate 			asn1_tlc_clear(ctx);
638*0Sstevel@tonic-gate 		/* SEQUENCE and SET must be constructed */
639*0Sstevel@tonic-gate 		} else if(!cst) {
640*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED);
641*0Sstevel@tonic-gate 			return 0;
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 		cont = *in;
645*0Sstevel@tonic-gate 		/* If indefinite length constructed find the real end */
646*0Sstevel@tonic-gate 		if(inf) {
647*0Sstevel@tonic-gate 			if(!asn1_collect(NULL, &p, plen, inf, -1, -1)) goto err;
648*0Sstevel@tonic-gate 			len = p - cont;
649*0Sstevel@tonic-gate 		} else {
650*0Sstevel@tonic-gate 			len = p - cont + plen;
651*0Sstevel@tonic-gate 			p += plen;
652*0Sstevel@tonic-gate 			buf.data = NULL;
653*0Sstevel@tonic-gate 		}
654*0Sstevel@tonic-gate 	} else if(cst) {
655*0Sstevel@tonic-gate 		buf.length = 0;
656*0Sstevel@tonic-gate 		buf.max = 0;
657*0Sstevel@tonic-gate 		buf.data = NULL;
658*0Sstevel@tonic-gate 		/* Should really check the internal tags are correct but
659*0Sstevel@tonic-gate 		 * some things may get this wrong. The relevant specs
660*0Sstevel@tonic-gate 		 * say that constructed string types should be OCTET STRINGs
661*0Sstevel@tonic-gate 		 * internally irrespective of the type. So instead just check
662*0Sstevel@tonic-gate 		 * for UNIVERSAL class and ignore the tag.
663*0Sstevel@tonic-gate 		 */
664*0Sstevel@tonic-gate 		if(!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL)) goto err;
665*0Sstevel@tonic-gate 		len = buf.length;
666*0Sstevel@tonic-gate 		/* Append a final null to string */
667*0Sstevel@tonic-gate 		if(!BUF_MEM_grow_clean(&buf, len + 1)) {
668*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
669*0Sstevel@tonic-gate 			return 0;
670*0Sstevel@tonic-gate 		}
671*0Sstevel@tonic-gate 		buf.data[len] = 0;
672*0Sstevel@tonic-gate 		cont = (unsigned char *)buf.data;
673*0Sstevel@tonic-gate 		free_cont = 1;
674*0Sstevel@tonic-gate 	} else {
675*0Sstevel@tonic-gate 		cont = p;
676*0Sstevel@tonic-gate 		len = plen;
677*0Sstevel@tonic-gate 		p += plen;
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	/* We now have content length and type: translate into a structure */
681*0Sstevel@tonic-gate 	if(!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err;
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	*in = p;
684*0Sstevel@tonic-gate 	ret = 1;
685*0Sstevel@tonic-gate 	err:
686*0Sstevel@tonic-gate 	if(free_cont && buf.data) OPENSSL_free(buf.data);
687*0Sstevel@tonic-gate 	return ret;
688*0Sstevel@tonic-gate }
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate /* Translate ASN1 content octets into a structure */
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it)
693*0Sstevel@tonic-gate {
694*0Sstevel@tonic-gate 	ASN1_VALUE **opval = NULL;
695*0Sstevel@tonic-gate 	ASN1_STRING *stmp;
696*0Sstevel@tonic-gate 	ASN1_TYPE *typ = NULL;
697*0Sstevel@tonic-gate 	int ret = 0;
698*0Sstevel@tonic-gate 	const ASN1_PRIMITIVE_FUNCS *pf;
699*0Sstevel@tonic-gate 	ASN1_INTEGER **tint;
700*0Sstevel@tonic-gate 	pf = it->funcs;
701*0Sstevel@tonic-gate 	if(pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
702*0Sstevel@tonic-gate 	/* If ANY type clear type and set pointer to internal value */
703*0Sstevel@tonic-gate 	if(it->utype == V_ASN1_ANY) {
704*0Sstevel@tonic-gate 		if(!*pval) {
705*0Sstevel@tonic-gate 			typ = ASN1_TYPE_new();
706*0Sstevel@tonic-gate 			*pval = (ASN1_VALUE *)typ;
707*0Sstevel@tonic-gate 		} else typ = (ASN1_TYPE *)*pval;
708*0Sstevel@tonic-gate 		if(utype != typ->type) ASN1_TYPE_set(typ, utype, NULL);
709*0Sstevel@tonic-gate 		opval = pval;
710*0Sstevel@tonic-gate 		pval = (ASN1_VALUE **)&typ->value.ptr;
711*0Sstevel@tonic-gate 	}
712*0Sstevel@tonic-gate 	switch(utype) {
713*0Sstevel@tonic-gate 		case V_ASN1_OBJECT:
714*0Sstevel@tonic-gate 		if(!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) goto err;
715*0Sstevel@tonic-gate 		break;
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 		case V_ASN1_NULL:
718*0Sstevel@tonic-gate 		if(len) {
719*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_NULL_IS_WRONG_LENGTH);
720*0Sstevel@tonic-gate 			goto err;
721*0Sstevel@tonic-gate 		}
722*0Sstevel@tonic-gate 		*pval = (ASN1_VALUE *)1;
723*0Sstevel@tonic-gate 		break;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		case V_ASN1_BOOLEAN:
726*0Sstevel@tonic-gate 		if(len != 1) {
727*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
728*0Sstevel@tonic-gate 			goto err;
729*0Sstevel@tonic-gate 		} else {
730*0Sstevel@tonic-gate 			ASN1_BOOLEAN *tbool;
731*0Sstevel@tonic-gate 			tbool = (ASN1_BOOLEAN *)pval;
732*0Sstevel@tonic-gate 			*tbool = *cont;
733*0Sstevel@tonic-gate 		}
734*0Sstevel@tonic-gate 		break;
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 		case V_ASN1_BIT_STRING:
737*0Sstevel@tonic-gate 		if(!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) goto err;
738*0Sstevel@tonic-gate 		break;
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 		case V_ASN1_INTEGER:
741*0Sstevel@tonic-gate 		case V_ASN1_NEG_INTEGER:
742*0Sstevel@tonic-gate 		case V_ASN1_ENUMERATED:
743*0Sstevel@tonic-gate 		case V_ASN1_NEG_ENUMERATED:
744*0Sstevel@tonic-gate 		tint = (ASN1_INTEGER **)pval;
745*0Sstevel@tonic-gate 		if(!c2i_ASN1_INTEGER(tint, &cont, len)) goto err;
746*0Sstevel@tonic-gate 		/* Fixup type to match the expected form */
747*0Sstevel@tonic-gate 		(*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
748*0Sstevel@tonic-gate 		break;
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 		case V_ASN1_OCTET_STRING:
751*0Sstevel@tonic-gate 		case V_ASN1_NUMERICSTRING:
752*0Sstevel@tonic-gate 		case V_ASN1_PRINTABLESTRING:
753*0Sstevel@tonic-gate 		case V_ASN1_T61STRING:
754*0Sstevel@tonic-gate 		case V_ASN1_VIDEOTEXSTRING:
755*0Sstevel@tonic-gate 		case V_ASN1_IA5STRING:
756*0Sstevel@tonic-gate 		case V_ASN1_UTCTIME:
757*0Sstevel@tonic-gate 		case V_ASN1_GENERALIZEDTIME:
758*0Sstevel@tonic-gate 		case V_ASN1_GRAPHICSTRING:
759*0Sstevel@tonic-gate 		case V_ASN1_VISIBLESTRING:
760*0Sstevel@tonic-gate 		case V_ASN1_GENERALSTRING:
761*0Sstevel@tonic-gate 		case V_ASN1_UNIVERSALSTRING:
762*0Sstevel@tonic-gate 		case V_ASN1_BMPSTRING:
763*0Sstevel@tonic-gate 		case V_ASN1_UTF8STRING:
764*0Sstevel@tonic-gate 		case V_ASN1_OTHER:
765*0Sstevel@tonic-gate 		case V_ASN1_SET:
766*0Sstevel@tonic-gate 		case V_ASN1_SEQUENCE:
767*0Sstevel@tonic-gate 		default:
768*0Sstevel@tonic-gate 		/* All based on ASN1_STRING and handled the same */
769*0Sstevel@tonic-gate 		if(!*pval) {
770*0Sstevel@tonic-gate 			stmp = ASN1_STRING_type_new(utype);
771*0Sstevel@tonic-gate 			if(!stmp) {
772*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
773*0Sstevel@tonic-gate 				goto err;
774*0Sstevel@tonic-gate 			}
775*0Sstevel@tonic-gate 			*pval = (ASN1_VALUE *)stmp;
776*0Sstevel@tonic-gate 		} else {
777*0Sstevel@tonic-gate 			stmp = (ASN1_STRING *)*pval;
778*0Sstevel@tonic-gate 			stmp->type = utype;
779*0Sstevel@tonic-gate 		}
780*0Sstevel@tonic-gate 		/* If we've already allocated a buffer use it */
781*0Sstevel@tonic-gate 		if(*free_cont) {
782*0Sstevel@tonic-gate 			if(stmp->data) OPENSSL_free(stmp->data);
783*0Sstevel@tonic-gate 			stmp->data = cont;
784*0Sstevel@tonic-gate 			stmp->length = len;
785*0Sstevel@tonic-gate 			*free_cont = 0;
786*0Sstevel@tonic-gate 		} else {
787*0Sstevel@tonic-gate 			if(!ASN1_STRING_set(stmp, cont, len)) {
788*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE);
789*0Sstevel@tonic-gate 				ASN1_STRING_free(stmp);
790*0Sstevel@tonic-gate 				*pval = NULL;
791*0Sstevel@tonic-gate 				goto err;
792*0Sstevel@tonic-gate 			}
793*0Sstevel@tonic-gate 		}
794*0Sstevel@tonic-gate 		break;
795*0Sstevel@tonic-gate 	}
796*0Sstevel@tonic-gate 	/* If ASN1_ANY and NULL type fix up value */
797*0Sstevel@tonic-gate 	if(typ && utype==V_ASN1_NULL) typ->value.ptr = NULL;
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	ret = 1;
800*0Sstevel@tonic-gate 	err:
801*0Sstevel@tonic-gate 	if(!ret)
802*0Sstevel@tonic-gate 		{
803*0Sstevel@tonic-gate 		ASN1_TYPE_free(typ);
804*0Sstevel@tonic-gate 		if (opval)
805*0Sstevel@tonic-gate 			*opval = NULL;
806*0Sstevel@tonic-gate 		}
807*0Sstevel@tonic-gate 	return ret;
808*0Sstevel@tonic-gate }
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate /* This function collects the asn1 data from a constructred string
811*0Sstevel@tonic-gate  * type into a buffer. The values of 'in' and 'len' should refer
812*0Sstevel@tonic-gate  * to the contents of the constructed type and 'inf' should be set
813*0Sstevel@tonic-gate  * if it is indefinite length. If 'buf' is NULL then we just want
814*0Sstevel@tonic-gate  * to find the end of the current structure: useful for indefinite
815*0Sstevel@tonic-gate  * length constructed stuff.
816*0Sstevel@tonic-gate  */
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass)
819*0Sstevel@tonic-gate {
820*0Sstevel@tonic-gate 	unsigned char *p, *q;
821*0Sstevel@tonic-gate 	long plen;
822*0Sstevel@tonic-gate 	char cst, ininf;
823*0Sstevel@tonic-gate 	p = *in;
824*0Sstevel@tonic-gate 	inf &= 1;
825*0Sstevel@tonic-gate 	/* If no buffer and not indefinite length constructed just pass over the encoded data */
826*0Sstevel@tonic-gate 	if(!buf && !inf) {
827*0Sstevel@tonic-gate 		*in += len;
828*0Sstevel@tonic-gate 		return 1;
829*0Sstevel@tonic-gate 	}
830*0Sstevel@tonic-gate 	while(len > 0) {
831*0Sstevel@tonic-gate 		q = p;
832*0Sstevel@tonic-gate 		/* Check for EOC */
833*0Sstevel@tonic-gate 		if(asn1_check_eoc(&p, len)) {
834*0Sstevel@tonic-gate 			/* EOC is illegal outside indefinite length constructed form */
835*0Sstevel@tonic-gate 			if(!inf) {
836*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC);
837*0Sstevel@tonic-gate 				return 0;
838*0Sstevel@tonic-gate 			}
839*0Sstevel@tonic-gate 			inf = 0;
840*0Sstevel@tonic-gate 			break;
841*0Sstevel@tonic-gate 		}
842*0Sstevel@tonic-gate 		if(!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, len, tag, aclass, 0, NULL)) {
843*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR);
844*0Sstevel@tonic-gate 			return 0;
845*0Sstevel@tonic-gate 		}
846*0Sstevel@tonic-gate 		/* If indefinite length constructed update max length */
847*0Sstevel@tonic-gate 		if(cst) {
848*0Sstevel@tonic-gate 			if(!asn1_collect(buf, &p, plen, ininf, tag, aclass)) return 0;
849*0Sstevel@tonic-gate 		} else {
850*0Sstevel@tonic-gate 			if(!collect_data(buf, &p, plen)) return 0;
851*0Sstevel@tonic-gate 		}
852*0Sstevel@tonic-gate 		len -= p - q;
853*0Sstevel@tonic-gate 	}
854*0Sstevel@tonic-gate 	if(inf) {
855*0Sstevel@tonic-gate 		ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC);
856*0Sstevel@tonic-gate 		return 0;
857*0Sstevel@tonic-gate 	}
858*0Sstevel@tonic-gate 	*in = p;
859*0Sstevel@tonic-gate 	return 1;
860*0Sstevel@tonic-gate }
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate static int collect_data(BUF_MEM *buf, unsigned char **p, long plen)
863*0Sstevel@tonic-gate {
864*0Sstevel@tonic-gate 		int len;
865*0Sstevel@tonic-gate 		if(buf) {
866*0Sstevel@tonic-gate 			len = buf->length;
867*0Sstevel@tonic-gate 			if(!BUF_MEM_grow_clean(buf, len + plen)) {
868*0Sstevel@tonic-gate 				ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE);
869*0Sstevel@tonic-gate 				return 0;
870*0Sstevel@tonic-gate 			}
871*0Sstevel@tonic-gate 			memcpy(buf->data + len, *p, plen);
872*0Sstevel@tonic-gate 		}
873*0Sstevel@tonic-gate 		*p += plen;
874*0Sstevel@tonic-gate 		return 1;
875*0Sstevel@tonic-gate }
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate /* Check for ASN1 EOC and swallow it if found */
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate static int asn1_check_eoc(unsigned char **in, long len)
880*0Sstevel@tonic-gate {
881*0Sstevel@tonic-gate 	unsigned char *p;
882*0Sstevel@tonic-gate 	if(len < 2) return 0;
883*0Sstevel@tonic-gate 	p = *in;
884*0Sstevel@tonic-gate 	if(!p[0] && !p[1]) {
885*0Sstevel@tonic-gate 		*in += 2;
886*0Sstevel@tonic-gate 		return 1;
887*0Sstevel@tonic-gate 	}
888*0Sstevel@tonic-gate 	return 0;
889*0Sstevel@tonic-gate }
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate /* Check an ASN1 tag and length: a bit like ASN1_get_object
892*0Sstevel@tonic-gate  * but it sets the length for indefinite length constructed
893*0Sstevel@tonic-gate  * form, we don't know the exact length but we can set an
894*0Sstevel@tonic-gate  * upper bound to the amount of data available minus the
895*0Sstevel@tonic-gate  * header length just read.
896*0Sstevel@tonic-gate  */
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst,
899*0Sstevel@tonic-gate 		unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx)
900*0Sstevel@tonic-gate {
901*0Sstevel@tonic-gate 	int i;
902*0Sstevel@tonic-gate 	int ptag, pclass;
903*0Sstevel@tonic-gate 	long plen;
904*0Sstevel@tonic-gate 	unsigned char *p, *q;
905*0Sstevel@tonic-gate 	p = *in;
906*0Sstevel@tonic-gate 	q = p;
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 	if(ctx && ctx->valid) {
909*0Sstevel@tonic-gate 		i = ctx->ret;
910*0Sstevel@tonic-gate 		plen = ctx->plen;
911*0Sstevel@tonic-gate 		pclass = ctx->pclass;
912*0Sstevel@tonic-gate 		ptag = ctx->ptag;
913*0Sstevel@tonic-gate 		p += ctx->hdrlen;
914*0Sstevel@tonic-gate 	} else {
915*0Sstevel@tonic-gate 		i = ASN1_get_object(&p, &plen, &ptag, &pclass, len);
916*0Sstevel@tonic-gate 		if(ctx) {
917*0Sstevel@tonic-gate 			ctx->ret = i;
918*0Sstevel@tonic-gate 			ctx->plen = plen;
919*0Sstevel@tonic-gate 			ctx->pclass = pclass;
920*0Sstevel@tonic-gate 			ctx->ptag = ptag;
921*0Sstevel@tonic-gate 			ctx->hdrlen = p - q;
922*0Sstevel@tonic-gate 			ctx->valid = 1;
923*0Sstevel@tonic-gate 			/* If definite length, and no error, length +
924*0Sstevel@tonic-gate 			 * header can't exceed total amount of data available.
925*0Sstevel@tonic-gate 			 */
926*0Sstevel@tonic-gate 			if(!(i & 0x81) && ((plen + ctx->hdrlen) > len)) {
927*0Sstevel@tonic-gate 				ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG);
928*0Sstevel@tonic-gate 				asn1_tlc_clear(ctx);
929*0Sstevel@tonic-gate 				return 0;
930*0Sstevel@tonic-gate 			}
931*0Sstevel@tonic-gate 		}
932*0Sstevel@tonic-gate 	}
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	if(i & 0x80) {
935*0Sstevel@tonic-gate 		ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER);
936*0Sstevel@tonic-gate 		asn1_tlc_clear(ctx);
937*0Sstevel@tonic-gate 		return 0;
938*0Sstevel@tonic-gate 	}
939*0Sstevel@tonic-gate 	if(exptag >= 0) {
940*0Sstevel@tonic-gate 		if((exptag != ptag) || (expclass != pclass)) {
941*0Sstevel@tonic-gate 			/* If type is OPTIONAL, not an error, but indicate missing
942*0Sstevel@tonic-gate 			 * type.
943*0Sstevel@tonic-gate 			 */
944*0Sstevel@tonic-gate 			if(opt) return -1;
945*0Sstevel@tonic-gate 			asn1_tlc_clear(ctx);
946*0Sstevel@tonic-gate 			ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG);
947*0Sstevel@tonic-gate 			return 0;
948*0Sstevel@tonic-gate 		}
949*0Sstevel@tonic-gate 		/* We have a tag and class match, so assume we are going to do something with it */
950*0Sstevel@tonic-gate 		asn1_tlc_clear(ctx);
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	if(i & 1) plen = len - (p - q);
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 	if(inf) *inf = i & 1;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	if(cst) *cst = i & V_ASN1_CONSTRUCTED;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	if(olen) *olen = plen;
960*0Sstevel@tonic-gate 	if(oclass) *oclass = pclass;
961*0Sstevel@tonic-gate 	if(otag) *otag = ptag;
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	*in = p;
964*0Sstevel@tonic-gate 	return 1;
965*0Sstevel@tonic-gate }
966