xref: /openbsd-src/lib/libcrypto/asn1/a_enum.c (revision 913ec974266f8a62ab2e5ca34a31d6e6f75b3cf0)
1 /* crypto/asn1/a_enum.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 /*
64  * Code for ENUMERATED type: identical to INTEGER apart from a different tag.
65  * for comments on encoding see a_int.c
66  */
67 
68 int i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *a, unsigned char **pp)
69 	{
70 	int pad=0,ret,r,i,t;
71 	unsigned char *p,*n,pb=0;
72 
73 	if ((a == NULL) || (a->data == NULL)) return(0);
74 	t=a->type;
75 	if (a->length == 0)
76 		ret=1;
77 	else
78 		{
79 		ret=a->length;
80 		i=a->data[0];
81 		if ((t == V_ASN1_ENUMERATED) && (i > 127)) {
82 			pad=1;
83 			pb=0;
84 		} else if(t == V_ASN1_NEG_ENUMERATED) {
85 			if(i>128) {
86 				pad=1;
87 				pb=0xFF;
88 			} else if(i == 128) {
89 				for(i = 1; i < a->length; i++) if(a->data[i]) {
90 						pad=1;
91 						pb=0xFF;
92 						break;
93 				}
94 			}
95 		}
96 		ret+=pad;
97 		}
98 	r=ASN1_object_size(0,ret,V_ASN1_ENUMERATED);
99 	if (pp == NULL) return(r);
100 	p= *pp;
101 
102 	ASN1_put_object(&p,0,ret,V_ASN1_ENUMERATED,V_ASN1_UNIVERSAL);
103 	if (pad) *(p++)=pb;
104 	if (a->length == 0)
105 		*(p++)=0;
106 	else if (t == V_ASN1_ENUMERATED)
107 		{
108 		memcpy(p,a->data,(unsigned int)a->length);
109 		p+=a->length;
110 		}
111 	else {
112 		/* Begin at the end of the encoding */
113 		n=a->data + a->length - 1;
114 		p += a->length - 1;
115 		i = a->length;
116 		/* Copy zeros to destination as long as source is zero */
117 		while(!*n) {
118 			*(p--) = 0;
119 			n--;
120 			i--;
121 		}
122 		/* Complement and increment next octet */
123 		*(p--) = ((*(n--)) ^ 0xff) + 1;
124 		i--;
125 		/* Complement any octets left */
126 		for(;i > 0; i--) *(p--) = *(n--) ^ 0xff;
127 		p += a->length;
128 	}
129 
130 	*pp=p;
131 	return(r);
132 	}
133 
134 ASN1_ENUMERATED *d2i_ASN1_ENUMERATED(ASN1_ENUMERATED **a, unsigned char **pp,
135 	     long length)
136 	{
137 	ASN1_ENUMERATED *ret=NULL;
138 	unsigned char *p,*to,*s;
139 	long len;
140 	int inf,tag,xclass;
141 	int i;
142 
143 	if ((a == NULL) || ((*a) == NULL))
144 		{
145 		if ((ret=ASN1_ENUMERATED_new()) == NULL) return(NULL);
146 		ret->type=V_ASN1_ENUMERATED;
147 		}
148 	else
149 		ret=(*a);
150 
151 	p= *pp;
152 	inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
153 	if (inf & 0x80)
154 		{
155 		i=ASN1_R_BAD_OBJECT_HEADER;
156 		goto err;
157 		}
158 
159 	if (tag != V_ASN1_ENUMERATED)
160 		{
161 		i=ASN1_R_EXPECTING_AN_ENUMERATED;
162 		goto err;
163 		}
164 
165 	/* We must Malloc stuff, even for 0 bytes otherwise it
166 	 * signifies a missing NULL parameter. */
167 	s=(unsigned char *)Malloc((int)len+1);
168 	if (s == NULL)
169 		{
170 		i=ERR_R_MALLOC_FAILURE;
171 		goto err;
172 		}
173 	to=s;
174 	if (*p & 0x80) /* a negative number */
175 		{
176 		ret->type=V_ASN1_NEG_ENUMERATED;
177 		if ((*p == 0xff) && (len != 1)) {
178 			p++;
179 			len--;
180 		}
181 		i = len;
182 		p += i - 1;
183 		to += i - 1;
184 		while((!*p) && i) {
185 			*(to--) = 0;
186 			i--;
187 			p--;
188 		}
189 		if(!i) {
190 			*s = 1;
191 			s[len] = 0;
192 			p += len;
193 			len++;
194 		} else {
195 			*(to--) = (*(p--) ^ 0xff) + 1;
196 			i--;
197 			for(;i > 0; i--) *(to--) = *(p--) ^ 0xff;
198 			p += len;
199 		}
200 	} else {
201 		ret->type=V_ASN1_ENUMERATED;
202 		if ((*p == 0) && (len != 1))
203 			{
204 			p++;
205 			len--;
206 			}
207 		memcpy(s,p,(int)len);
208 		p+=len;
209 	}
210 
211 	if (ret->data != NULL) Free((char *)ret->data);
212 	ret->data=s;
213 	ret->length=(int)len;
214 	if (a != NULL) (*a)=ret;
215 	*pp=p;
216 	return(ret);
217 err:
218 	ASN1err(ASN1_F_D2I_ASN1_ENUMERATED,i);
219 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
220 		ASN1_ENUMERATED_free(ret);
221 	return(NULL);
222 	}
223 
224 int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
225 	{
226 	int i,j,k;
227 	unsigned char buf[sizeof(long)+1];
228 	long d;
229 
230 	a->type=V_ASN1_ENUMERATED;
231 	if (a->length < (sizeof(long)+1))
232 		{
233 		if (a->data != NULL)
234 			Free((char *)a->data);
235 		if ((a->data=(unsigned char *)Malloc(sizeof(long)+1)) != NULL)
236 			memset((char *)a->data,0,sizeof(long)+1);
237 		}
238 	if (a->data == NULL)
239 		{
240 		ASN1err(ASN1_F_ASN1_ENUMERATED_SET,ERR_R_MALLOC_FAILURE);
241 		return(0);
242 		}
243 	d=v;
244 	if (d < 0)
245 		{
246 		d= -d;
247 		a->type=V_ASN1_NEG_ENUMERATED;
248 		}
249 
250 	for (i=0; i<sizeof(long); i++)
251 		{
252 		if (d == 0) break;
253 		buf[i]=(int)d&0xff;
254 		d>>=8;
255 		}
256 	j=0;
257 	for (k=i-1; k >=0; k--)
258 		a->data[j++]=buf[k];
259 	a->length=j;
260 	return(1);
261 	}
262 
263 long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
264 	{
265 	int neg=0,i;
266 	long r=0;
267 
268 	if (a == NULL) return(0L);
269 	i=a->type;
270 	if (i == V_ASN1_NEG_ENUMERATED)
271 		neg=1;
272 	else if (i != V_ASN1_ENUMERATED)
273 		return(0);
274 
275 	if (a->length > sizeof(long))
276 		{
277 		/* hmm... a bit ugly */
278 		return(0xffffffffL);
279 		}
280 	if (a->data == NULL)
281 		return(0);
282 
283 	for (i=0; i<a->length; i++)
284 		{
285 		r<<=8;
286 		r|=(unsigned char)a->data[i];
287 		}
288 	if (neg) r= -r;
289 	return(r);
290 	}
291 
292 ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
293 	{
294 	ASN1_ENUMERATED *ret;
295 	int len,j;
296 
297 	if (ai == NULL)
298 		ret=ASN1_ENUMERATED_new();
299 	else
300 		ret=ai;
301 	if (ret == NULL)
302 		{
303 		ASN1err(ASN1_F_BN_TO_ASN1_ENUMERATED,ERR_R_NESTED_ASN1_ERROR);
304 		goto err;
305 		}
306 	if(bn->neg) ret->type = V_ASN1_NEG_ENUMERATED;
307 	else ret->type=V_ASN1_ENUMERATED;
308 	j=BN_num_bits(bn);
309 	len=((j == 0)?0:((j/8)+1));
310 	ret->data=(unsigned char *)Malloc(len+4);
311 	ret->length=BN_bn2bin(bn,ret->data);
312 	return(ret);
313 err:
314 	if (ret != ai) ASN1_ENUMERATED_free(ret);
315 	return(NULL);
316 	}
317 
318 BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn)
319 	{
320 	BIGNUM *ret;
321 
322 	if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL)
323 		ASN1err(ASN1_F_ASN1_ENUMERATED_TO_BN,ASN1_R_BN_LIB);
324 	if(ai->type == V_ASN1_NEG_ENUMERATED) bn->neg = 1;
325 	return(ret);
326 	}
327