asn1_par.c revision 160815
1204076Spjd/* crypto/asn1/asn1_par.c */
2204076Spjd/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3211877Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * This package is an SSL implementation written
6204076Spjd * by Eric Young (eay@cryptsoft.com).
7204076Spjd * The implementation was written so as to conform with Netscapes SSL.
8204076Spjd *
9204076Spjd * This library is free for commercial and non-commercial use as long as
10204076Spjd * the following conditions are aheared to.  The following conditions
11204076Spjd * apply to all code found in this distribution, be it the RC4, RSA,
12204076Spjd * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13204076Spjd * included with this distribution is covered by the same copyright terms
14204076Spjd * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15204076Spjd *
16204076Spjd * Copyright remains Eric Young's, and as such any Copyright notices in
17204076Spjd * the code are not to be removed.
18204076Spjd * If this package is used in a product, Eric Young should be given attribution
19204076Spjd * as the author of the parts of the library used.
20204076Spjd * This can be in the form of a textual message at program startup or
21204076Spjd * in documentation (online or textual) provided with the package.
22204076Spjd *
23204076Spjd * Redistribution and use in source and binary forms, with or without
24204076Spjd * modification, are permitted provided that the following conditions
25204076Spjd * are met:
26204076Spjd * 1. Redistributions of source code must retain the copyright
27204076Spjd *    notice, this list of conditions and the following disclaimer.
28204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
29204076Spjd *    notice, this list of conditions and the following disclaimer in the
30204076Spjd *    documentation and/or other materials provided with the distribution.
31204076Spjd * 3. All advertising materials mentioning features or use of this software
32204076Spjd *    must display the following acknowledgement:
33204076Spjd *    "This product includes cryptographic software written by
34204076Spjd *     Eric Young (eay@cryptsoft.com)"
35204076Spjd *    The word 'cryptographic' can be left out if the rouines from the library
36204076Spjd *    being used are not cryptographic related :-).
37204076Spjd * 4. If you include any Windows specific code (or a derivative thereof) from
38204076Spjd *    the apps directory (application code) you must include an acknowledgement:
39204076Spjd *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40204076Spjd *
41204076Spjd * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46213009Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51204076Spjd * SUCH DAMAGE.
52204076Spjd *
53204076Spjd * The licence and distribution terms for any publically available version or
54204076Spjd * derivative of this code cannot be changed.  i.e. this code cannot simply be
55204076Spjd * copied and put under another distribution licence
56204076Spjd * [including the GNU Public Licence.]
57204076Spjd */
58212038Spjd
59204076Spjd#include <stdio.h>
60204076Spjd#include "cryptlib.h"
61204076Spjd#include <openssl/buffer.h>
62211977Spjd#include <openssl/objects.h>
63204076Spjd#include <openssl/asn1.h>
64204076Spjd
65204076Spjdstatic int asn1_print_info(BIO *bp, int tag, int xclass,int constructed,
66204076Spjd	int indent);
67204076Spjdstatic int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
68204076Spjd	int offset, int depth, int indent, int dump);
69204076Spjdstatic int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
70204076Spjd	     int indent)
71204076Spjd	{
72204076Spjd	static const char fmt[]="%-18s";
73204076Spjd	static const char fmt2[]="%2d %-15s";
74204076Spjd	char str[128];
75204076Spjd	const char *p,*p2=NULL;
76204076Spjd
77204076Spjd	if (constructed & V_ASN1_CONSTRUCTED)
78204076Spjd		p="cons: ";
79211984Spjd	else
80211984Spjd		p="prim: ";
81204076Spjd	if (BIO_write(bp,p,6) < 6) goto err;
82204076Spjd	BIO_indent(bp,indent,128);
83204076Spjd
84204076Spjd	p=str;
85204076Spjd	if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
86204076Spjd		BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag);
87204076Spjd	else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
88204076Spjd		BIO_snprintf(str,sizeof str,"cont [ %d ]",tag);
89204076Spjd	else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
90204076Spjd		BIO_snprintf(str,sizeof str,"appl [ %d ]",tag);
91204076Spjd	else if (tag > 30)
92204076Spjd		BIO_snprintf(str,sizeof str,"<ASN1 %d>",tag);
93204076Spjd	else
94204076Spjd		p = ASN1_tag2str(tag);
95204076Spjd
96204076Spjd	if (p2 != NULL)
97204076Spjd		{
98204076Spjd		if (BIO_printf(bp,fmt2,tag,p2) <= 0) goto err;
99204076Spjd		}
100204076Spjd	else
101204076Spjd		{
102204076Spjd		if (BIO_printf(bp,fmt,p) <= 0) goto err;
103204076Spjd		}
104204076Spjd	return(1);
105204076Spjderr:
106204076Spjd	return(0);
107204076Spjd	}
108204076Spjd
109204076Spjdint ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
110204076Spjd	{
111211877Spjd	return(asn1_parse2(bp,&pp,len,0,0,indent,0));
112211877Spjd	}
113211877Spjd
114211877Spjdint ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump)
115211877Spjd	{
116211877Spjd	return(asn1_parse2(bp,&pp,len,0,0,indent,dump));
117211877Spjd	}
118211877Spjd
119211877Spjdstatic int asn1_parse2(BIO *bp, const unsigned char **pp, long length, int offset,
120211877Spjd	     int depth, int indent, int dump)
121211877Spjd	{
122211877Spjd	const unsigned char *p,*ep,*tot,*op,*opp;
123211877Spjd	long len;
124211877Spjd	int tag,xclass,ret=0;
125211877Spjd	int nl,hl,j,r;
126211877Spjd	ASN1_OBJECT *o=NULL;
127211877Spjd	ASN1_OCTET_STRING *os=NULL;
128211877Spjd	/* ASN1_BMPSTRING *bmp=NULL;*/
129211877Spjd	int dump_indent;
130211877Spjd
131204076Spjd#if 0
132204076Spjd	dump_indent = indent;
133204076Spjd#else
134204076Spjd	dump_indent = 6;	/* Because we know BIO_dump_indent() */
135204076Spjd#endif
136204076Spjd	p= *pp;
137204076Spjd	tot=p+length;
138204076Spjd	op=p-1;
139204076Spjd	while ((p < tot) && (op < p))
140204076Spjd		{
141204076Spjd		op=p;
142204076Spjd		j=ASN1_get_object(&p,&len,&tag,&xclass,length);
143204076Spjd#ifdef LINT
144204076Spjd		j=j;
145204076Spjd#endif
146204076Spjd		if (j & 0x80)
147204076Spjd			{
148204076Spjd			if (BIO_write(bp,"Error in encoding\n",18) <= 0)
149204076Spjd				goto end;
150204076Spjd			ret=0;
151204076Spjd			goto end;
152204076Spjd			}
153204076Spjd		hl=(p-op);
154204076Spjd		length-=hl;
155204076Spjd		/* if j == 0x21 it is a constructed indefinite length object */
156210879Spjd		if (BIO_printf(bp,"%5ld:",(long)offset+(long)(op- *pp))
157210879Spjd			<= 0) goto end;
158210879Spjd
159204076Spjd		if (j != (V_ASN1_CONSTRUCTED | 1))
160204076Spjd			{
161204076Spjd			if (BIO_printf(bp,"d=%-2d hl=%ld l=%4ld ",
162204076Spjd				depth,(long)hl,len) <= 0)
163210879Spjd				goto end;
164210879Spjd			}
165210879Spjd		else
166204076Spjd			{
167204076Spjd			if (BIO_printf(bp,"d=%-2d hl=%ld l=inf  ",
168204076Spjd				depth,(long)hl) <= 0)
169204076Spjd				goto end;
170204076Spjd			}
171204076Spjd		if (!asn1_print_info(bp,tag,xclass,j,(indent)?depth:0))
172204076Spjd			goto end;
173204076Spjd		if (j & V_ASN1_CONSTRUCTED)
174204076Spjd			{
175204076Spjd			ep=p+len;
176204076Spjd			if (BIO_write(bp,"\n",1) <= 0) goto end;
177204076Spjd			if (len > length)
178204076Spjd				{
179204076Spjd				BIO_printf(bp,
180204076Spjd					"length is greater than %ld\n",length);
181204076Spjd				ret=0;
182204076Spjd				goto end;
183204076Spjd				}
184204076Spjd			if ((j == 0x21) && (len == 0))
185204076Spjd				{
186204076Spjd				for (;;)
187204076Spjd					{
188204076Spjd					r=asn1_parse2(bp,&p,(long)(tot-p),
189204076Spjd						offset+(p - *pp),depth+1,
190204076Spjd						indent,dump);
191204076Spjd					if (r == 0) { ret=0; goto end; }
192204076Spjd					if ((r == 2) || (p >= tot)) break;
193204076Spjd					}
194204076Spjd				}
195204076Spjd			else
196204076Spjd				while (p < ep)
197204076Spjd					{
198204076Spjd					r=asn1_parse2(bp,&p,(long)len,
199204076Spjd						offset+(p - *pp),depth+1,
200204076Spjd						indent,dump);
201204076Spjd					if (r == 0) { ret=0; goto end; }
202204076Spjd					}
203204076Spjd			}
204204076Spjd		else if (xclass != 0)
205204076Spjd			{
206204076Spjd			p+=len;
207204076Spjd			if (BIO_write(bp,"\n",1) <= 0) goto end;
208204076Spjd			}
209204076Spjd		else
210204076Spjd			{
211204076Spjd			nl=0;
212204076Spjd			if (	(tag == V_ASN1_PRINTABLESTRING) ||
213204076Spjd				(tag == V_ASN1_T61STRING) ||
214204076Spjd				(tag == V_ASN1_IA5STRING) ||
215204076Spjd				(tag == V_ASN1_VISIBLESTRING) ||
216204076Spjd				(tag == V_ASN1_UTCTIME) ||
217204076Spjd				(tag == V_ASN1_GENERALIZEDTIME))
218204076Spjd				{
219204076Spjd				if (BIO_write(bp,":",1) <= 0) goto end;
220204076Spjd				if ((len > 0) &&
221204076Spjd					BIO_write(bp,(const char *)p,(int)len)
222204076Spjd					!= (int)len)
223204076Spjd					goto end;
224204076Spjd				}
225204076Spjd			else if (tag == V_ASN1_OBJECT)
226204076Spjd				{
227204076Spjd				opp=op;
228204076Spjd				if (d2i_ASN1_OBJECT(&o,&opp,len+hl) != NULL)
229204076Spjd					{
230204076Spjd					if (BIO_write(bp,":",1) <= 0) goto end;
231204076Spjd					i2a_ASN1_OBJECT(bp,o);
232204076Spjd					}
233204076Spjd				else
234204076Spjd					{
235204076Spjd					if (BIO_write(bp,":BAD OBJECT",11) <= 0)
236204076Spjd						goto end;
237204076Spjd					}
238204076Spjd				}
239204076Spjd			else if (tag == V_ASN1_BOOLEAN)
240204076Spjd				{
241204076Spjd				int ii;
242204076Spjd
243204076Spjd				opp=op;
244204076Spjd				ii=d2i_ASN1_BOOLEAN(NULL,&opp,len+hl);
245204076Spjd				if (ii < 0)
246204076Spjd					{
247204076Spjd					if (BIO_write(bp,"Bad boolean\n",12))
248204076Spjd						goto end;
249204076Spjd					}
250204076Spjd				BIO_printf(bp,":%d",ii);
251204076Spjd				}
252204076Spjd			else if (tag == V_ASN1_BMPSTRING)
253204076Spjd				{
254204076Spjd				/* do the BMP thang */
255204076Spjd				}
256204076Spjd			else if (tag == V_ASN1_OCTET_STRING)
257204076Spjd				{
258204076Spjd				int i,printable=1;
259204076Spjd
260204076Spjd				opp=op;
261204076Spjd				os=d2i_ASN1_OCTET_STRING(NULL,&opp,len+hl);
262204076Spjd				if (os != NULL && os->length > 0)
263204076Spjd					{
264204076Spjd					opp = os->data;
265204076Spjd					/* testing whether the octet string is
266204076Spjd					 * printable */
267204076Spjd					for (i=0; i<os->length; i++)
268204076Spjd						{
269204076Spjd						if ((	(opp[i] < ' ') &&
270204076Spjd							(opp[i] != '\n') &&
271204076Spjd							(opp[i] != '\r') &&
272204076Spjd							(opp[i] != '\t')) ||
273204076Spjd							(opp[i] > '~'))
274204076Spjd							{
275204076Spjd							printable=0;
276204076Spjd							break;
277204076Spjd							}
278204076Spjd						}
279204076Spjd					if (printable)
280204076Spjd					/* printable string */
281204076Spjd						{
282204076Spjd						if (BIO_write(bp,":",1) <= 0)
283204076Spjd							goto end;
284204076Spjd						if (BIO_write(bp,(const char *)opp,
285204076Spjd							os->length) <= 0)
286204076Spjd							goto end;
287204076Spjd						}
288204076Spjd					else if (!dump)
289204076Spjd					/* not printable => print octet string
290204076Spjd					 * as hex dump */
291204076Spjd						{
292204076Spjd						if (BIO_write(bp,"[HEX DUMP]:",11) <= 0)
293204076Spjd							goto end;
294204076Spjd						for (i=0; i<os->length; i++)
295204076Spjd							{
296204076Spjd							if (BIO_printf(bp,"%02X"
297204076Spjd								, opp[i]) <= 0)
298204076Spjd								goto end;
299204076Spjd							}
300204076Spjd						}
301204076Spjd					else
302204076Spjd					/* print the normal dump */
303204076Spjd						{
304204076Spjd						if (!nl)
305204076Spjd							{
306204076Spjd							if (BIO_write(bp,"\n",1) <= 0)
307204076Spjd								goto end;
308204076Spjd							}
309204076Spjd						if (BIO_dump_indent(bp,
310204076Spjd							(const char *)opp,
311204076Spjd							((dump == -1 || dump >
312204076Spjd							os->length)?os->length:dump),
313204076Spjd							dump_indent) <= 0)
314204076Spjd							goto end;
315204076Spjd						nl=1;
316204076Spjd						}
317204076Spjd					}
318204076Spjd				if (os != NULL)
319204076Spjd					{
320204076Spjd					M_ASN1_OCTET_STRING_free(os);
321214276Spjd					os=NULL;
322204076Spjd					}
323204076Spjd				}
324214275Spjd			else if (tag == V_ASN1_INTEGER)
325214275Spjd				{
326209182Spjd				ASN1_INTEGER *bs;
327204076Spjd				int i;
328204076Spjd
329204076Spjd				opp=op;
330212038Spjd				bs=d2i_ASN1_INTEGER(NULL,&opp,len+hl);
331204076Spjd				if (bs != NULL)
332204076Spjd					{
333204076Spjd					if (BIO_write(bp,":",1) <= 0) goto end;
334204076Spjd					if (bs->type == V_ASN1_NEG_INTEGER)
335204076Spjd						if (BIO_write(bp,"-",1) <= 0)
336204076Spjd							goto end;
337204076Spjd					for (i=0; i<bs->length; i++)
338213009Spjd						{
339204076Spjd						if (BIO_printf(bp,"%02X",
340204076Spjd							bs->data[i]) <= 0)
341204076Spjd							goto end;
342204076Spjd						}
343204076Spjd					if (bs->length == 0)
344204076Spjd						{
345204076Spjd						if (BIO_write(bp,"00",2) <= 0)
346204076Spjd							goto end;
347204076Spjd						}
348204076Spjd					}
349204076Spjd				else
350204076Spjd					{
351212038Spjd					if (BIO_write(bp,"BAD INTEGER",11) <= 0)
352212038Spjd						goto end;
353212038Spjd					}
354212038Spjd				M_ASN1_INTEGER_free(bs);
355212038Spjd				}
356212038Spjd			else if (tag == V_ASN1_ENUMERATED)
357212038Spjd				{
358212038Spjd				ASN1_ENUMERATED *bs;
359204076Spjd				int i;
360204076Spjd
361204076Spjd				opp=op;
362204076Spjd				bs=d2i_ASN1_ENUMERATED(NULL,&opp,len+hl);
363204076Spjd				if (bs != NULL)
364204076Spjd					{
365204076Spjd					if (BIO_write(bp,":",1) <= 0) goto end;
366204076Spjd					if (bs->type == V_ASN1_NEG_ENUMERATED)
367204076Spjd						if (BIO_write(bp,"-",1) <= 0)
368204076Spjd							goto end;
369204076Spjd					for (i=0; i<bs->length; i++)
370204076Spjd						{
371204076Spjd						if (BIO_printf(bp,"%02X",
372212038Spjd							bs->data[i]) <= 0)
373212038Spjd							goto end;
374204076Spjd						}
375204076Spjd					if (bs->length == 0)
376204076Spjd						{
377211977Spjd						if (BIO_write(bp,"00",2) <= 0)
378211984Spjd							goto end;
379211984Spjd						}
380204076Spjd					}
381211977Spjd				else
382204076Spjd					{
383204076Spjd					if (BIO_write(bp,"BAD ENUMERATED",11) <= 0)
384204076Spjd						goto end;
385213009Spjd					}
386213009Spjd				M_ASN1_ENUMERATED_free(bs);
387210880Spjd				}
388212038Spjd			else if (len > 0 && dump)
389212038Spjd				{
390212038Spjd				if (!nl)
391207371Spjd					{
392207371Spjd					if (BIO_write(bp,"\n",1) <= 0)
393207371Spjd						goto end;
394207371Spjd					}
395207371Spjd				if (BIO_dump_indent(bp,(const char *)p,
396207371Spjd					((dump == -1 || dump > len)?len:dump),
397204076Spjd					dump_indent) <= 0)
398213007Spjd					goto end;
399213007Spjd				nl=1;
400213007Spjd				}
401213007Spjd
402213007Spjd			if (!nl)
403213007Spjd				{
404213007Spjd				if (BIO_write(bp,"\n",1) <= 0) goto end;
405213007Spjd				}
406213007Spjd			p+=len;
407213007Spjd			if ((tag == V_ASN1_EOC) && (xclass == 0))
408213007Spjd				{
409213007Spjd				ret=2; /* End of sequence */
410213007Spjd				goto end;
411204076Spjd				}
412212038Spjd			}
413204076Spjd		length-=len;
414204076Spjd		}
415204076Spjd	ret=1;
416204076Spjdend:
417204076Spjd	if (o != NULL) ASN1_OBJECT_free(o);
418213007Spjd	if (os != NULL) M_ASN1_OCTET_STRING_free(os);
419204076Spjd	*pp=p;
420204076Spjd	return(ret);
421204076Spjd	}
422204076Spjd
423204076Spjdconst char *ASN1_tag2str(int tag)
424204076Spjd{
425204076Spjd	static const char *tag2str[] = {
426204076Spjd	 "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */
427204076Spjd	 "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */
428204076Spjd	 "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>", 	    /* 10-13 */
429204076Spjd	"<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET", 		    /* 15-17 */
430204076Spjd	"NUMERICSTRING", "PRINTABLESTRING", "T61STRING",	    /* 18-20 */
431204076Spjd	"VIDEOTEXSTRING", "IA5STRING", "UTCTIME","GENERALIZEDTIME", /* 21-24 */
432204076Spjd	"GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING",	    /* 25-27 */
433204076Spjd	"UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING"		    /* 28-30 */
434204076Spjd	};
435204076Spjd
436204076Spjd	if((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
437204076Spjd							tag &= ~0x100;
438204076Spjd
439204076Spjd	if(tag < 0 || tag > 30) return "(unknown)";
440204076Spjd	return tag2str[tag];
441204076Spjd}
442204076Spjd
443204076Spjd