xref: /openbsd/lib/libcrypto/asn1/asn1_lib.c (revision d485f761)
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 #include <openssl/asn1_mac.h>
63 
64 static int asn1_get_length(unsigned char **pp,int *inf,long *rl,int max);
65 static void asn1_put_length(unsigned char **pp, int length);
66 const char *ASN1_version="ASN.1" OPENSSL_VERSION_PTEXT;
67 
68 int ASN1_check_infinite_end(unsigned char **p, long len)
69 	{
70 	/* If there is 0 or 1 byte left, the length check should pick
71 	 * things up */
72 	if (len <= 0)
73 		return(1);
74 	else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0))
75 		{
76 		(*p)+=2;
77 		return(1);
78 		}
79 	return(0);
80 	}
81 
82 
83 int ASN1_get_object(unsigned char **pp, long *plength, int *ptag, int *pclass,
84 	     long omax)
85 	{
86 	int i,ret;
87 	long l;
88 	unsigned char *p= *pp;
89 	int tag,xclass,inf;
90 	long max=omax;
91 
92 	if (!max) goto err;
93 	ret=(*p&V_ASN1_CONSTRUCTED);
94 	xclass=(*p&V_ASN1_PRIVATE);
95 	i= *p&V_ASN1_PRIMITIVE_TAG;
96 	if (i == V_ASN1_PRIMITIVE_TAG)
97 		{		/* high-tag */
98 		p++;
99 		if (--max == 0) goto err;
100 		l=0;
101 		while (*p&0x80)
102 			{
103 			l<<=7L;
104 			l|= *(p++)&0x7f;
105 			if (--max == 0) goto err;
106 			}
107 		l<<=7L;
108 		l|= *(p++)&0x7f;
109 		tag=(int)l;
110 		}
111 	else
112 		{
113 		tag=i;
114 		p++;
115 		if (--max == 0) goto err;
116 		}
117 	*ptag=tag;
118 	*pclass=xclass;
119 	if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err;
120 
121 #if 0
122 	fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d  (%d > %d)\n",
123 		(int)p,*plength,omax,(int)*pp,(int)(p+ *plength),
124 		(int)(omax+ *pp));
125 
126 #endif
127 #if 0
128 	if ((p+ *plength) > (omax+ *pp))
129 		{
130 		ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_TOO_LONG);
131 		/* Set this so that even if things are not long enough
132 		 * the values are set correctly */
133 		ret|=0x80;
134 		}
135 #endif
136 	*pp=p;
137 	return(ret|inf);
138 err:
139 	ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_HEADER_TOO_LONG);
140 	return(0x80);
141 	}
142 
143 static int asn1_get_length(unsigned char **pp, int *inf, long *rl, int max)
144 	{
145 	unsigned char *p= *pp;
146 	long ret=0;
147 	int i;
148 
149 	if (max-- < 1) return(0);
150 	if (*p == 0x80)
151 		{
152 		*inf=1;
153 		ret=0;
154 		p++;
155 		}
156 	else
157 		{
158 		*inf=0;
159 		i= *p&0x7f;
160 		if (*(p++) & 0x80)
161 			{
162 			if (max-- == 0) return(0);
163 			while (i-- > 0)
164 				{
165 				ret<<=8L;
166 				ret|= *(p++);
167 				if (max-- == 0) return(0);
168 				}
169 			}
170 		else
171 			ret=i;
172 		}
173 	*pp=p;
174 	*rl=ret;
175 	return(1);
176 	}
177 
178 /* class 0 is constructed
179  * constructed == 2 for indefinite length constructed */
180 void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
181 	     int xclass)
182 	{
183 	unsigned char *p= *pp;
184 	int i, ttag;
185 
186 	i=(constructed)?V_ASN1_CONSTRUCTED:0;
187 	i|=(xclass&V_ASN1_PRIVATE);
188 	if (tag < 31)
189 		*(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG);
190 	else
191 		{
192 		*(p++)=i|V_ASN1_PRIMITIVE_TAG;
193 		for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7;
194 		ttag = i;
195 		while(i-- > 0)
196 			{
197 			p[i] = tag & 0x7f;
198 			if(i != (ttag - 1)) p[i] |= 0x80;
199 			tag >>= 7;
200 			}
201 		p += ttag;
202 		}
203 	if ((constructed == 2) && (length == 0))
204 		*(p++)=0x80; /* der_put_length would output 0 instead */
205 	else
206 		asn1_put_length(&p,length);
207 	*pp=p;
208 	}
209 
210 static void asn1_put_length(unsigned char **pp, int length)
211 	{
212 	unsigned char *p= *pp;
213 	int i,l;
214 	if (length <= 127)
215 		*(p++)=(unsigned char)length;
216 	else
217 		{
218 		l=length;
219 		for (i=0; l > 0; i++)
220 			l>>=8;
221 		*(p++)=i|0x80;
222 		l=i;
223 		while (i-- > 0)
224 			{
225 			p[i]=length&0xff;
226 			length>>=8;
227 			}
228 		p+=l;
229 		}
230 	*pp=p;
231 	}
232 
233 int ASN1_object_size(int constructed, int length, int tag)
234 	{
235 	int ret;
236 
237 	ret=length;
238 	ret++;
239 	if (tag >= 31)
240 		{
241 		while (tag > 0)
242 			{
243 			tag>>=7;
244 			ret++;
245 			}
246 		}
247 	if ((length == 0) && (constructed == 2))
248 		ret+=2;
249 	ret++;
250 	if (length > 127)
251 		{
252 		while (length > 0)
253 			{
254 			length>>=8;
255 			ret++;
256 			}
257 		}
258 	return(ret);
259 	}
260 
261 int asn1_Finish(ASN1_CTX *c)
262 	{
263 	if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos))
264 		{
265 		if (!ASN1_check_infinite_end(&c->p,c->slen))
266 			{
267 			c->error=ERR_R_MISSING_ASN1_EOS;
268 			return(0);
269 			}
270 		}
271 	if (	((c->slen != 0) && !(c->inf & 1)) ||
272 		((c->slen < 0) && (c->inf & 1)))
273 		{
274 		c->error=ERR_R_ASN1_LENGTH_MISMATCH;
275 		return(0);
276 		}
277 	return(1);
278 	}
279 
280 int asn1_GetSequence(ASN1_CTX *c, long *length)
281 	{
282 	unsigned char *q;
283 
284 	q=c->p;
285 	c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass),
286 		*length);
287 	if (c->inf & 0x80)
288 		{
289 		c->error=ERR_R_BAD_GET_ASN1_OBJECT_CALL;
290 		return(0);
291 		}
292 	if (c->tag != V_ASN1_SEQUENCE)
293 		{
294 		c->error=ERR_R_EXPECTING_AN_ASN1_SEQUENCE;
295 		return(0);
296 		}
297 	(*length)-=(c->p-q);
298 	if (c->max && (*length < 0))
299 		{
300 		c->error=ERR_R_ASN1_LENGTH_MISMATCH;
301 		return(0);
302 		}
303 	if (c->inf == (1|V_ASN1_CONSTRUCTED))
304 		c->slen= *length;
305 	c->eos=0;
306 	return(1);
307 	}
308 
309 ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str)
310 	{
311 	ASN1_STRING *ret;
312 
313 	if (str == NULL) return(NULL);
314 	if ((ret=ASN1_STRING_type_new(str->type)) == NULL)
315 		return(NULL);
316 	if (!ASN1_STRING_set(ret,str->data,str->length))
317 		{
318 		ASN1_STRING_free(ret);
319 		return(NULL);
320 		}
321 	ret->flags = str->flags;
322 	return(ret);
323 	}
324 
325 int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
326 	{
327 	unsigned char *c;
328 	const char *data=_data;
329 
330 	if (len < 0)
331 		{
332 		if (data == NULL)
333 			return(0);
334 		else
335 			len=strlen(data);
336 		}
337 	if ((str->length < len) || (str->data == NULL))
338 		{
339 		c=str->data;
340 		if (c == NULL)
341 			str->data=OPENSSL_malloc(len+1);
342 		else
343 			str->data=OPENSSL_realloc(c,len+1);
344 
345 		if (str->data == NULL)
346 			{
347 			str->data=c;
348 			return(0);
349 			}
350 		}
351 	str->length=len;
352 	if (data != NULL)
353 		{
354 		memcpy(str->data,data,len);
355 		/* an allowance for strings :-) */
356 		str->data[len]='\0';
357 		}
358 	return(1);
359 	}
360 
361 ASN1_STRING *ASN1_STRING_new(void)
362 	{
363 	return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING));
364 	}
365 
366 
367 ASN1_STRING *ASN1_STRING_type_new(int type)
368 	{
369 	ASN1_STRING *ret;
370 
371 	ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING));
372 	if (ret == NULL)
373 		{
374 		ASN1err(ASN1_F_ASN1_STRING_TYPE_NEW,ERR_R_MALLOC_FAILURE);
375 		return(NULL);
376 		}
377 	ret->length=0;
378 	ret->type=type;
379 	ret->data=NULL;
380 	ret->flags=0;
381 	return(ret);
382 	}
383 
384 void ASN1_STRING_free(ASN1_STRING *a)
385 	{
386 	if (a == NULL) return;
387 	if (a->data != NULL) OPENSSL_free(a->data);
388 	OPENSSL_free(a);
389 	}
390 
391 int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b)
392 	{
393 	int i;
394 
395 	i=(a->length-b->length);
396 	if (i == 0)
397 		{
398 		i=memcmp(a->data,b->data,a->length);
399 		if (i == 0)
400 			return(a->type-b->type);
401 		else
402 			return(i);
403 		}
404 	else
405 		return(i);
406 	}
407 
408 void asn1_add_error(unsigned char *address, int offset)
409 	{
410 	char buf1[16],buf2[16];
411 
412 	sprintf(buf1,"%lu",(unsigned long)address);
413 	sprintf(buf2,"%d",offset);
414 	ERR_add_error_data(4,"address=",buf1," offset=",buf2);
415 	}
416 
417 int ASN1_STRING_length(ASN1_STRING *x)
418 { return M_ASN1_STRING_length(x); }
419 
420 void ASN1_STRING_length_set(ASN1_STRING *x, int len)
421 { M_ASN1_STRING_length_set(x, len); return; }
422 
423 int ASN1_STRING_type(ASN1_STRING *x)
424 { return M_ASN1_STRING_type(x); }
425 
426 unsigned char * ASN1_STRING_data(ASN1_STRING *x)
427 { return M_ASN1_STRING_data(x); }
428