1 /* $OpenBSD: a_object.c,v 1.31 2018/04/25 11:48:21 tb Exp $ */
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 <limits.h>
60 #include <stdio.h>
61 #include <string.h>
62 
63 #include <openssl/asn1.h>
64 #include <openssl/bn.h>
65 #include <openssl/err.h>
66 #include <openssl/buffer.h>
67 #include <openssl/objects.h>
68 
69 int
70 i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
71 {
72 	unsigned char *p;
73 	int objsize;
74 
75 	if ((a == NULL) || (a->data == NULL))
76 		return (0);
77 
78 	objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
79 	if (pp == NULL)
80 		return objsize;
81 
82 	p = *pp;
83 	ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
84 	memcpy(p, a->data, a->length);
85 	p += a->length;
86 
87 	*pp = p;
88 	return (objsize);
89 }
90 
91 int
92 a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
93 {
94 	int i, first, len = 0, c, use_bn;
95 	char ftmp[24], *tmp = ftmp;
96 	int tmpsize = sizeof ftmp;
97 	const char *p;
98 	unsigned long l;
99 	BIGNUM *bl = NULL;
100 
101 	if (num == 0)
102 		return (0);
103 	else if (num == -1)
104 		num = strlen(buf);
105 
106 	p = buf;
107 	c = *(p++);
108 	num--;
109 	if ((c >= '0') && (c <= '2')) {
110 		first= c-'0';
111 	} else {
112 		ASN1error(ASN1_R_FIRST_NUM_TOO_LARGE);
113 		goto err;
114 	}
115 
116 	if (num <= 0) {
117 		ASN1error(ASN1_R_MISSING_SECOND_NUMBER);
118 		goto err;
119 	}
120 	c = *(p++);
121 	num--;
122 	for (;;) {
123 		if (num <= 0)
124 			break;
125 		if ((c != '.') && (c != ' ')) {
126 			ASN1error(ASN1_R_INVALID_SEPARATOR);
127 			goto err;
128 		}
129 		l = 0;
130 		use_bn = 0;
131 		for (;;) {
132 			if (num <= 0)
133 				break;
134 			num--;
135 			c = *(p++);
136 			if ((c == ' ') || (c == '.'))
137 				break;
138 			if ((c < '0') || (c > '9')) {
139 				ASN1error(ASN1_R_INVALID_DIGIT);
140 				goto err;
141 			}
142 			if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
143 				use_bn = 1;
144 				if (!bl)
145 					bl = BN_new();
146 				if (!bl || !BN_set_word(bl, l))
147 					goto err;
148 			}
149 			if (use_bn) {
150 				if (!BN_mul_word(bl, 10L) ||
151 				    !BN_add_word(bl, c-'0'))
152 					goto err;
153 			} else
154 				l = l * 10L + (long)(c - '0');
155 		}
156 		if (len == 0) {
157 			if ((first < 2) && (l >= 40)) {
158 				ASN1error(ASN1_R_SECOND_NUMBER_TOO_LARGE);
159 				goto err;
160 			}
161 			if (use_bn) {
162 				if (!BN_add_word(bl, first * 40))
163 					goto err;
164 			} else
165 				l += (long)first * 40;
166 		}
167 		i = 0;
168 		if (use_bn) {
169 			int blsize;
170 			blsize = BN_num_bits(bl);
171 			blsize = (blsize + 6) / 7;
172 			if (blsize > tmpsize) {
173 				if (tmp != ftmp)
174 					free(tmp);
175 				tmpsize = blsize + 32;
176 				tmp = malloc(tmpsize);
177 				if (!tmp)
178 					goto err;
179 			}
180 			while (blsize--)
181 				tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
182 		} else {
183 
184 			for (;;) {
185 				tmp[i++] = (unsigned char)l & 0x7f;
186 				l >>= 7L;
187 				if (l == 0L)
188 					break;
189 			}
190 
191 		}
192 		if (out != NULL) {
193 			if (len + i > olen) {
194 				ASN1error(ASN1_R_BUFFER_TOO_SMALL);
195 				goto err;
196 			}
197 			while (--i > 0)
198 				out[len++] = tmp[i]|0x80;
199 			out[len++] = tmp[0];
200 		} else
201 			len += i;
202 	}
203 	if (tmp != ftmp)
204 		free(tmp);
205 	BN_free(bl);
206 	return (len);
207 
208 err:
209 	if (tmp != ftmp)
210 		free(tmp);
211 	BN_free(bl);
212 	return (0);
213 }
214 
215 int
216 i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a)
217 {
218 	return OBJ_obj2txt(buf, buf_len, a, 0);
219 }
220 
221 int
222 i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a)
223 {
224 	char *tmp = NULL;
225 	size_t tlen = 256;
226 	int i = -1;
227 
228 	if ((a == NULL) || (a->data == NULL))
229 		return(BIO_write(bp, "NULL", 4));
230 	if ((tmp = malloc(tlen)) == NULL)
231 		return -1;
232 	i = i2t_ASN1_OBJECT(tmp, tlen, a);
233 	if (i > (int)(tlen - 1)) {
234 		freezero(tmp, tlen);
235 		if ((tmp = malloc(i + 1)) == NULL)
236 			return -1;
237 		tlen = i + 1;
238 		i = i2t_ASN1_OBJECT(tmp, tlen, a);
239 	}
240 	if (i <= 0)
241 		i = BIO_write(bp, "<INVALID>", 9);
242 	else
243 		i = BIO_write(bp, tmp, i);
244 	freezero(tmp, tlen);
245 	return (i);
246 }
247 
248 ASN1_OBJECT *
249 d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, long length)
250 {
251 	const unsigned char *p;
252 	long len;
253 	int tag, xclass;
254 	int inf, i;
255 	ASN1_OBJECT *ret = NULL;
256 
257 	p = *pp;
258 	inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
259 	if (inf & 0x80) {
260 		i = ASN1_R_BAD_OBJECT_HEADER;
261 		goto err;
262 	}
263 
264 	if (tag != V_ASN1_OBJECT) {
265 		i = ASN1_R_EXPECTING_AN_OBJECT;
266 		goto err;
267 	}
268 	ret = c2i_ASN1_OBJECT(a, &p, len);
269 	if (ret)
270 		*pp = p;
271 	return ret;
272 
273 err:
274 	ASN1error(i);
275 	return (NULL);
276 }
277 
278 ASN1_OBJECT *
279 c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, long len)
280 {
281 	ASN1_OBJECT *ret;
282 	const unsigned char *p;
283 	unsigned char *data;
284 	int i, length;
285 
286 	/*
287 	 * Sanity check OID encoding:
288 	 * - need at least one content octet
289 	 * - MSB must be clear in the last octet
290 	 * - can't have leading 0x80 in subidentifiers, see: X.690 8.19.2
291 	 */
292 	if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
293 	    p[len - 1] & 0x80) {
294 		ASN1error(ASN1_R_INVALID_OBJECT_ENCODING);
295 		return (NULL);
296 	}
297 
298 	/* Now 0 < len <= INT_MAX, so the cast is safe. */
299 	length = (int)len;
300 	for (i = 0; i < length; i++, p++) {
301 		if (*p == 0x80 && (!i || !(p[-1] & 0x80))) {
302 			ASN1error(ASN1_R_INVALID_OBJECT_ENCODING);
303 			return (NULL);
304 		}
305 	}
306 
307 	/* only the ASN1_OBJECTs from the 'table' will have values
308 	 * for ->sn or ->ln */
309 	if ((a == NULL) || ((*a) == NULL) ||
310 	    !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
311 		if ((ret = ASN1_OBJECT_new()) == NULL)
312 			return (NULL);
313 	} else
314 		ret = *a;
315 
316 	p = *pp;
317 
318 	/* detach data from object */
319 	data = (unsigned char *)ret->data;
320 	freezero(data, ret->length);
321 
322 	data = malloc(length);
323 	if (data == NULL) {
324 		ASN1error(ERR_R_MALLOC_FAILURE);
325 		goto err;
326 	}
327 
328 	memcpy(data, p, length);
329 
330 	/* reattach data to object, after which it remains const */
331 	ret->data = data;
332 	ret->length = length;
333 	ret->sn = NULL;
334 	ret->ln = NULL;
335 	ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
336 	p += length;
337 
338 	if (a != NULL)
339 		*a = ret;
340 	*pp = p;
341 	return (ret);
342 
343 err:
344 	if (a == NULL || ret != *a)
345 		ASN1_OBJECT_free(ret);
346 	return (NULL);
347 }
348 
349 ASN1_OBJECT *
350 ASN1_OBJECT_new(void)
351 {
352 	ASN1_OBJECT *ret;
353 
354 	ret = malloc(sizeof(ASN1_OBJECT));
355 	if (ret == NULL) {
356 		ASN1error(ERR_R_MALLOC_FAILURE);
357 		return (NULL);
358 	}
359 	ret->length = 0;
360 	ret->data = NULL;
361 	ret->nid = 0;
362 	ret->sn = NULL;
363 	ret->ln = NULL;
364 	ret->flags = ASN1_OBJECT_FLAG_DYNAMIC;
365 	return (ret);
366 }
367 
368 void
369 ASN1_OBJECT_free(ASN1_OBJECT *a)
370 {
371 	if (a == NULL)
372 		return;
373 	if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) {
374 		free((void *)a->sn);
375 		free((void *)a->ln);
376 		a->sn = a->ln = NULL;
377 	}
378 	if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) {
379 		freezero((void *)a->data, a->length);
380 		a->data = NULL;
381 		a->length = 0;
382 	}
383 	if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC)
384 		free(a);
385 }
386 
387 ASN1_OBJECT *
388 ASN1_OBJECT_create(int nid, unsigned char *data, int len,
389     const char *sn, const char *ln)
390 {
391 	ASN1_OBJECT o;
392 
393 	o.sn = sn;
394 	o.ln = ln;
395 	o.data = data;
396 	o.nid = nid;
397 	o.length = len;
398 	o.flags = ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
399 	    ASN1_OBJECT_FLAG_DYNAMIC_DATA;
400 	return (OBJ_dup(&o));
401 }
402