xref: /openbsd-src/lib/libcrypto/asn1/asn1_lib.c (revision 428837d1af6ee7883726f5a6f82d6bae10ac0025)
1 /* crypto/asn1/asn1_lib.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <stdio.h>
60 #include "cryptlib.h"
61 #include <openssl/asn1.h>
62 
63 static int asn1_get_length(unsigned char **pp,int *inf,long *rl,int max);
64 static void asn1_put_length(unsigned char **pp, int length);
65 const char *ASN1_version="ASN.1" OPENSSL_VERSION_PTEXT;
66 
67 int ASN1_check_infinite_end(unsigned char **p, long len)
68 	{
69 	/* If there is 0 or 1 byte left, the length check should pick
70 	 * things up */
71 	if (len <= 0)
72 		return(1);
73 	else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0))
74 		{
75 		(*p)+=2;
76 		return(1);
77 		}
78 	return(0);
79 	}
80 
81 
82 int ASN1_get_object(unsigned char **pp, long *plength, int *ptag, int *pclass,
83 	     long omax)
84 	{
85 	int i,ret;
86 	long l;
87 	unsigned char *p= *pp;
88 	int tag,xclass,inf;
89 	long max=omax;
90 
91 	if (!max) goto err;
92 	ret=(*p&V_ASN1_CONSTRUCTED);
93 	xclass=(*p&V_ASN1_PRIVATE);
94 	i= *p&V_ASN1_PRIMITIVE_TAG;
95 	if (i == V_ASN1_PRIMITIVE_TAG)
96 		{		/* high-tag */
97 		p++;
98 		if (--max == 0) goto err;
99 		l=0;
100 		while (*p&0x80)
101 			{
102 			l<<=7L;
103 			l|= *(p++)&0x7f;
104 			if (--max == 0) goto err;
105 			}
106 		l<<=7L;
107 		l|= *(p++)&0x7f;
108 		tag=(int)l;
109 		}
110 	else
111 		{
112 		tag=i;
113 		p++;
114 		if (--max == 0) goto err;
115 		}
116 	*ptag=tag;
117 	*pclass=xclass;
118 	if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err;
119 
120 #if 0
121 	fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d  (%d > %d)\n",
122 		(int)p,*plength,omax,(int)*pp,(int)(p+ *plength),
123 		(int)(omax+ *pp));
124 
125 #endif
126 	if (*plength > (omax - (*pp - p)))
127 		{
128 		ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_TOO_LONG);
129 		/* Set this so that even if things are not long enough
130 		 * the values are set correctly */
131 		ret|=0x80;
132 		}
133 	*pp=p;
134 	return(ret|inf);
135 err:
136 	ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_HEADER_TOO_LONG);
137 	return(0x80);
138 	}
139 
140 static int asn1_get_length(unsigned char **pp, int *inf, long *rl, int max)
141 	{
142 	unsigned char *p= *pp;
143 	long ret=0;
144 	int i;
145 
146 	if (max-- < 1) return(0);
147 	if (*p == 0x80)
148 		{
149 		*inf=1;
150 		ret=0;
151 		p++;
152 		}
153 	else
154 		{
155 		*inf=0;
156 		i= *p&0x7f;
157 		if (*(p++) & 0x80)
158 			{
159 			if (i > sizeof(long))
160 				return 0;
161 			if (max-- == 0) return(0);
162 			while (i-- > 0)
163 				{
164 				ret<<=8L;
165 				ret|= *(p++);
166 				if (max-- == 0) return(0);
167 				}
168 			}
169 		else
170 			ret=i;
171 		}
172 	if (ret < 0)
173 		return 0;
174 	*pp=p;
175 	*rl=ret;
176 	return(1);
177 	}
178 
179 /* class 0 is constructed
180  * constructed == 2 for indefinite length constructed */
181 void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
182 	     int xclass)
183 	{
184 	unsigned char *p= *pp;
185 	int i, ttag;
186 
187 	i=(constructed)?V_ASN1_CONSTRUCTED:0;
188 	i|=(xclass&V_ASN1_PRIVATE);
189 	if (tag < 31)
190 		*(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG);
191 	else
192 		{
193 		*(p++)=i|V_ASN1_PRIMITIVE_TAG;
194 		for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7;
195 		ttag = i;
196 		while(i-- > 0)
197 			{
198 			p[i] = tag & 0x7f;
199 			if(i != (ttag - 1)) p[i] |= 0x80;
200 			tag >>= 7;
201 			}
202 		p += ttag;
203 		}
204 	if ((constructed == 2) && (length == 0))
205 		*(p++)=0x80; /* der_put_length would output 0 instead */
206 	else
207 		asn1_put_length(&p,length);
208 	*pp=p;
209 	}
210 
211 static void asn1_put_length(unsigned char **pp, int length)
212 	{
213 	unsigned char *p= *pp;
214 	int i,l;
215 	if (length <= 127)
216 		*(p++)=(unsigned char)length;
217 	else
218 		{
219 		l=length;
220 		for (i=0; l > 0; i++)
221 			l>>=8;
222 		*(p++)=i|0x80;
223 		l=i;
224 		while (i-- > 0)
225 			{
226 			p[i]=length&0xff;
227 			length>>=8;
228 			}
229 		p+=l;
230 		}
231 	*pp=p;
232 	}
233 
234 int ASN1_object_size(int constructed, int length, int tag)
235 	{
236 	int ret;
237 
238 	ret=length;
239 	ret++;
240 	if (tag >= 31)
241 		{
242 		while (tag > 0)
243 			{
244 			tag>>=7;
245 			ret++;
246 			}
247 		}
248 	if ((length == 0) && (constructed == 2))
249 		ret+=2;
250 	ret++;
251 	if (length > 127)
252 		{
253 		while (length > 0)
254 			{
255 			length>>=8;
256 			ret++;
257 			}
258 		}
259 	return(ret);
260 	}
261 
262 int asn1_Finish(ASN1_CTX *c)
263 	{
264 	if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos))
265 		{
266 		if (!ASN1_check_infinite_end(&c->p,c->slen))
267 			{
268 			c->error=ERR_R_MISSING_ASN1_EOS;
269 			return(0);
270 			}
271 		}
272 	if (	((c->slen != 0) && !(c->inf & 1)) ||
273 		((c->slen < 0) && (c->inf & 1)))
274 		{
275 		c->error=ERR_R_ASN1_LENGTH_MISMATCH;
276 		return(0);
277 		}
278 	return(1);
279 	}
280 
281 int asn1_GetSequence(ASN1_CTX *c, long *length)
282 	{
283 	unsigned char *q;
284 
285 	q=c->p;
286 	c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass),
287 		*length);
288 	if (c->inf & 0x80)
289 		{
290 		c->error=ERR_R_BAD_GET_ASN1_OBJECT_CALL;
291 		return(0);
292 		}
293 	if (c->tag != V_ASN1_SEQUENCE)
294 		{
295 		c->error=ERR_R_EXPECTING_AN_ASN1_SEQUENCE;
296 		return(0);
297 		}
298 	(*length)-=(c->p-q);
299 	if (c->max && (*length < 0))
300 		{
301 		c->error=ERR_R_ASN1_LENGTH_MISMATCH;
302 		return(0);
303 		}
304 	if (c->inf == (1|V_ASN1_CONSTRUCTED))
305 		c->slen= *length+ *(c->pp)-c->p;
306 	c->eos=0;
307 	return(1);
308 	}
309 
310 ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str)
311 	{
312 	ASN1_STRING *ret;
313 
314 	if (str == NULL) return(NULL);
315 	if ((ret=ASN1_STRING_type_new(str->type)) == NULL)
316 		return(NULL);
317 	if (!ASN1_STRING_set(ret,str->data,str->length))
318 		{
319 		ASN1_STRING_free(ret);
320 		return(NULL);
321 		}
322 	ret->flags = str->flags;
323 	return(ret);
324 	}
325 
326 int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
327 	{
328 	unsigned char *c;
329 	const char *data=_data;
330 
331 	if (len < 0)
332 		{
333 		if (data == NULL)
334 			return(0);
335 		else
336 			len=strlen(data);
337 		}
338 	if ((str->length < len) || (str->data == NULL))
339 		{
340 		c=str->data;
341 		if (c == NULL)
342 			str->data=OPENSSL_malloc(len+1);
343 		else
344 			str->data=OPENSSL_realloc(c,len+1);
345 
346 		if (str->data == NULL)
347 			{
348 			str->data=c;
349 			return(0);
350 			}
351 		}
352 	str->length=len;
353 	if (data != NULL)
354 		{
355 		memcpy(str->data,data,len);
356 		/* an allowance for strings :-) */
357 		str->data[len]='\0';
358 		}
359 	return(1);
360 	}
361 
362 ASN1_STRING *ASN1_STRING_new(void)
363 	{
364 	return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING));
365 	}
366 
367 
368 ASN1_STRING *ASN1_STRING_type_new(int type)
369 	{
370 	ASN1_STRING *ret;
371 
372 	ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING));
373 	if (ret == NULL)
374 		{
375 		ASN1err(ASN1_F_ASN1_STRING_TYPE_NEW,ERR_R_MALLOC_FAILURE);
376 		return(NULL);
377 		}
378 	ret->length=0;
379 	ret->type=type;
380 	ret->data=NULL;
381 	ret->flags=0;
382 	return(ret);
383 	}
384 
385 void ASN1_STRING_free(ASN1_STRING *a)
386 	{
387 	if (a == NULL) return;
388 	if (a->data != NULL) OPENSSL_free(a->data);
389 	OPENSSL_free(a);
390 	}
391 
392 int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b)
393 	{
394 	int i;
395 
396 	i=(a->length-b->length);
397 	if (i == 0)
398 		{
399 		i=memcmp(a->data,b->data,a->length);
400 		if (i == 0)
401 			return(a->type-b->type);
402 		else
403 			return(i);
404 		}
405 	else
406 		return(i);
407 	}
408 
409 void asn1_add_error(unsigned char *address, int offset)
410 	{
411 	char buf1[DECIMAL_SIZE(address)+1],buf2[DECIMAL_SIZE(offset)+1];
412 
413 	sprintf(buf1,"%lu",(unsigned long)address);
414 	sprintf(buf2,"%d",offset);
415 	ERR_add_error_data(4,"address=",buf1," offset=",buf2);
416 	}
417 
418 int ASN1_STRING_length(ASN1_STRING *x)
419 { return M_ASN1_STRING_length(x); }
420 
421 void ASN1_STRING_length_set(ASN1_STRING *x, int len)
422 { M_ASN1_STRING_length_set(x, len); return; }
423 
424 int ASN1_STRING_type(ASN1_STRING *x)
425 { return M_ASN1_STRING_type(x); }
426 
427 unsigned char * ASN1_STRING_data(ASN1_STRING *x)
428 { return M_ASN1_STRING_data(x); }
429