xref: /freebsd/crypto/heimdal/lib/asn1/der_get.c (revision 1b7487592987c91020063a311a14dc15b6e58075)
1b528cefcSMark Murray /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "der_locl.h"
35b528cefcSMark Murray 
36b528cefcSMark Murray /*
37b528cefcSMark Murray  * All decoding functions take a pointer `p' to first position in
38b528cefcSMark Murray  * which to read, from the left, `len' which means the maximum number
39b528cefcSMark Murray  * of characters we are able to read, `ret' were the value will be
40b528cefcSMark Murray  * returned and `size' where the number of used bytes is stored.
41b528cefcSMark Murray  * Either 0 or an error code is returned.
42b528cefcSMark Murray  */
43b528cefcSMark Murray 
44c19800e8SDoug Rabson int
45b528cefcSMark Murray der_get_unsigned (const unsigned char *p, size_t len,
46b528cefcSMark Murray 		  unsigned *ret, size_t *size)
47b528cefcSMark Murray {
48b528cefcSMark Murray     unsigned val = 0;
49b528cefcSMark Murray     size_t oldlen = len;
50b528cefcSMark Murray 
51*1b748759SDimitry Andric     if (len == sizeof(val) + 1 && p[0] == 0)
52c19800e8SDoug Rabson 	;
53*1b748759SDimitry Andric     else if (len > sizeof(val))
54*1b748759SDimitry Andric 	return ASN1_OVERRUN;
55*1b748759SDimitry Andric 
56*1b748759SDimitry Andric     while (len--)
57*1b748759SDimitry Andric 	val = val * 256 + *p++;
58*1b748759SDimitry Andric     *ret = val;
59*1b748759SDimitry Andric     if(size) *size = oldlen;
60*1b748759SDimitry Andric     return 0;
61*1b748759SDimitry Andric }
62*1b748759SDimitry Andric 
63*1b748759SDimitry Andric int
64*1b748759SDimitry Andric der_get_unsigned64 (const unsigned char *p, size_t len,
65*1b748759SDimitry Andric 		    uint64_t *ret, size_t *size)
66*1b748759SDimitry Andric {
67*1b748759SDimitry Andric     uint64_t val = 0;
68*1b748759SDimitry Andric     size_t oldlen = len;
69*1b748759SDimitry Andric 
70*1b748759SDimitry Andric     if (len == sizeof(val) + 1 && p[0] == 0)
71*1b748759SDimitry Andric 	;
72*1b748759SDimitry Andric     else if (len > sizeof(val))
73c19800e8SDoug Rabson 	return ASN1_OVERRUN;
74c19800e8SDoug Rabson 
75b528cefcSMark Murray     while (len--)
76b528cefcSMark Murray 	val = val * 256 + *p++;
77b528cefcSMark Murray     *ret = val;
78b528cefcSMark Murray     if(size) *size = oldlen;
79b528cefcSMark Murray     return 0;
80b528cefcSMark Murray }
81b528cefcSMark Murray 
82b528cefcSMark Murray int
83c19800e8SDoug Rabson der_get_integer (const unsigned char *p, size_t len,
84b528cefcSMark Murray 		 int *ret, size_t *size)
85b528cefcSMark Murray {
86b528cefcSMark Murray     int val = 0;
87b528cefcSMark Murray     size_t oldlen = len;
88b528cefcSMark Murray 
89*1b748759SDimitry Andric     if (len > sizeof(val))
90*1b748759SDimitry Andric 	return ASN1_OVERRUN;
91*1b748759SDimitry Andric 
92*1b748759SDimitry Andric     if (len > 0) {
93*1b748759SDimitry Andric 	val = (signed char)*p++;
94*1b748759SDimitry Andric 	while (--len)
95*1b748759SDimitry Andric 	    val = val * 256 + *p++;
96*1b748759SDimitry Andric     }
97*1b748759SDimitry Andric     *ret = val;
98*1b748759SDimitry Andric     if(size) *size = oldlen;
99*1b748759SDimitry Andric     return 0;
100*1b748759SDimitry Andric }
101*1b748759SDimitry Andric 
102*1b748759SDimitry Andric int
103*1b748759SDimitry Andric der_get_integer64 (const unsigned char *p, size_t len,
104*1b748759SDimitry Andric 		   int64_t *ret, size_t *size)
105*1b748759SDimitry Andric {
106*1b748759SDimitry Andric     int64_t val = 0;
107*1b748759SDimitry Andric     size_t oldlen = len;
108*1b748759SDimitry Andric 
109*1b748759SDimitry Andric     if (len > sizeof(val))
110c19800e8SDoug Rabson 	return ASN1_OVERRUN;
111c19800e8SDoug Rabson 
1128373020dSJacques Vidrine     if (len > 0) {
113b528cefcSMark Murray 	val = (signed char)*p++;
1148373020dSJacques Vidrine 	while (--len)
115b528cefcSMark Murray 	    val = val * 256 + *p++;
1168373020dSJacques Vidrine     }
117b528cefcSMark Murray     *ret = val;
118b528cefcSMark Murray     if(size) *size = oldlen;
119b528cefcSMark Murray     return 0;
120b528cefcSMark Murray }
121b528cefcSMark Murray 
122b528cefcSMark Murray int
123b528cefcSMark Murray der_get_length (const unsigned char *p, size_t len,
124b528cefcSMark Murray 		size_t *val, size_t *size)
125b528cefcSMark Murray {
126b528cefcSMark Murray     size_t v;
127b528cefcSMark Murray 
128b528cefcSMark Murray     if (len <= 0)
129b528cefcSMark Murray 	return ASN1_OVERRUN;
130b528cefcSMark Murray     --len;
131b528cefcSMark Murray     v = *p++;
132b528cefcSMark Murray     if (v < 128) {
133b528cefcSMark Murray 	*val = v;
134b528cefcSMark Murray 	if(size) *size = 1;
135b528cefcSMark Murray     } else {
136b528cefcSMark Murray 	int e;
137b528cefcSMark Murray 	size_t l;
138b528cefcSMark Murray 	unsigned tmp;
139b528cefcSMark Murray 
140b528cefcSMark Murray 	if(v == 0x80){
141b528cefcSMark Murray 	    *val = ASN1_INDEFINITE;
142b528cefcSMark Murray 	    if(size) *size = 1;
143b528cefcSMark Murray 	    return 0;
144b528cefcSMark Murray 	}
145b528cefcSMark Murray 	v &= 0x7F;
146b528cefcSMark Murray 	if (len < v)
147b528cefcSMark Murray 	    return ASN1_OVERRUN;
148b528cefcSMark Murray 	e = der_get_unsigned (p, v, &tmp, &l);
149b528cefcSMark Murray 	if(e) return e;
150b528cefcSMark Murray 	*val = tmp;
151b528cefcSMark Murray 	if(size) *size = l + 1;
152b528cefcSMark Murray     }
153b528cefcSMark Murray     return 0;
154b528cefcSMark Murray }
155b528cefcSMark Murray 
156b528cefcSMark Murray int
157c19800e8SDoug Rabson der_get_boolean(const unsigned char *p, size_t len, int *data, size_t *size)
158b528cefcSMark Murray {
159c19800e8SDoug Rabson     if(len < 1)
160c19800e8SDoug Rabson 	return ASN1_OVERRUN;
161c19800e8SDoug Rabson     if(*p != 0)
162c19800e8SDoug Rabson 	*data = 1;
163c19800e8SDoug Rabson     else
164c19800e8SDoug Rabson 	*data = 0;
165c19800e8SDoug Rabson     *size = 1;
166c19800e8SDoug Rabson     return 0;
167c19800e8SDoug Rabson }
168c19800e8SDoug Rabson 
169c19800e8SDoug Rabson int
170c19800e8SDoug Rabson der_get_general_string (const unsigned char *p, size_t len,
171c19800e8SDoug Rabson 			heim_general_string *str, size_t *size)
172c19800e8SDoug Rabson {
173c19800e8SDoug Rabson     const unsigned char *p1;
174b528cefcSMark Murray     char *s;
175b528cefcSMark Murray 
176c19800e8SDoug Rabson     p1 = memchr(p, 0, len);
177c19800e8SDoug Rabson     if (p1 != NULL) {
178c19800e8SDoug Rabson 	/*
179c19800e8SDoug Rabson 	 * Allow trailing NULs. We allow this since MIT Kerberos sends
180c19800e8SDoug Rabson 	 * an strings in the NEED_PREAUTH case that includes a
181c19800e8SDoug Rabson 	 * trailing NUL.
182c19800e8SDoug Rabson 	 */
183ae771770SStanislav Sedov 	while ((size_t)(p1 - p) < len && *p1 == '\0')
184c19800e8SDoug Rabson 	    p1++;
185ae771770SStanislav Sedov        if ((size_t)(p1 - p) != len)
186c19800e8SDoug Rabson 	    return ASN1_BAD_CHARACTER;
187c19800e8SDoug Rabson     }
188c19800e8SDoug Rabson     if (len > len + 1)
189c19800e8SDoug Rabson 	return ASN1_BAD_LENGTH;
190c19800e8SDoug Rabson 
191b528cefcSMark Murray     s = malloc (len + 1);
192b528cefcSMark Murray     if (s == NULL)
193b528cefcSMark Murray 	return ENOMEM;
194b528cefcSMark Murray     memcpy (s, p, len);
195b528cefcSMark Murray     s[len] = '\0';
196b528cefcSMark Murray     *str = s;
197b528cefcSMark Murray     if(size) *size = len;
198b528cefcSMark Murray     return 0;
199b528cefcSMark Murray }
200b528cefcSMark Murray 
201b528cefcSMark Murray int
202c19800e8SDoug Rabson der_get_utf8string (const unsigned char *p, size_t len,
203c19800e8SDoug Rabson 		    heim_utf8_string *str, size_t *size)
204c19800e8SDoug Rabson {
205c19800e8SDoug Rabson     return der_get_general_string(p, len, str, size);
206c19800e8SDoug Rabson }
207c19800e8SDoug Rabson 
208c19800e8SDoug Rabson int
209c19800e8SDoug Rabson der_get_printable_string(const unsigned char *p, size_t len,
210c19800e8SDoug Rabson 			 heim_printable_string *str, size_t *size)
211c19800e8SDoug Rabson {
212ae771770SStanislav Sedov     str->length = len;
213ae771770SStanislav Sedov     str->data = malloc(len + 1);
214ae771770SStanislav Sedov     if (str->data == NULL)
215ae771770SStanislav Sedov 	return ENOMEM;
216ae771770SStanislav Sedov     memcpy(str->data, p, len);
217ae771770SStanislav Sedov     ((char *)str->data)[len] = '\0';
218ae771770SStanislav Sedov     if(size) *size = len;
219ae771770SStanislav Sedov     return 0;
220c19800e8SDoug Rabson }
221c19800e8SDoug Rabson 
222c19800e8SDoug Rabson int
223c19800e8SDoug Rabson der_get_ia5_string(const unsigned char *p, size_t len,
224c19800e8SDoug Rabson 		   heim_ia5_string *str, size_t *size)
225c19800e8SDoug Rabson {
226ae771770SStanislav Sedov     return der_get_printable_string(p, len, str, size);
227c19800e8SDoug Rabson }
228c19800e8SDoug Rabson 
229c19800e8SDoug Rabson int
230c19800e8SDoug Rabson der_get_bmp_string (const unsigned char *p, size_t len,
231c19800e8SDoug Rabson 		    heim_bmp_string *data, size_t *size)
232c19800e8SDoug Rabson {
233c19800e8SDoug Rabson     size_t i;
234c19800e8SDoug Rabson 
235c19800e8SDoug Rabson     if (len & 1)
236c19800e8SDoug Rabson 	return ASN1_BAD_FORMAT;
237c19800e8SDoug Rabson     data->length = len / 2;
238c19800e8SDoug Rabson     if (data->length > UINT_MAX/sizeof(data->data[0]))
239c19800e8SDoug Rabson 	return ERANGE;
240c19800e8SDoug Rabson     data->data = malloc(data->length * sizeof(data->data[0]));
241c19800e8SDoug Rabson     if (data->data == NULL && data->length != 0)
242c19800e8SDoug Rabson 	return ENOMEM;
243c19800e8SDoug Rabson 
244c19800e8SDoug Rabson     for (i = 0; i < data->length; i++) {
245c19800e8SDoug Rabson 	data->data[i] = (p[0] << 8) | p[1];
246c19800e8SDoug Rabson 	p += 2;
247ae771770SStanislav Sedov 	/* check for NUL in the middle of the string */
248ae771770SStanislav Sedov 	if (data->data[i] == 0 && i != (data->length - 1)) {
249ae771770SStanislav Sedov 	    free(data->data);
250ae771770SStanislav Sedov 	    data->data = NULL;
251ae771770SStanislav Sedov 	    data->length = 0;
252ae771770SStanislav Sedov 	    return ASN1_BAD_CHARACTER;
253ae771770SStanislav Sedov 	}
254c19800e8SDoug Rabson     }
255c19800e8SDoug Rabson     if (size) *size = len;
256c19800e8SDoug Rabson 
257c19800e8SDoug Rabson     return 0;
258c19800e8SDoug Rabson }
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson int
261c19800e8SDoug Rabson der_get_universal_string (const unsigned char *p, size_t len,
262c19800e8SDoug Rabson 			  heim_universal_string *data, size_t *size)
263c19800e8SDoug Rabson {
264c19800e8SDoug Rabson     size_t i;
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson     if (len & 3)
267c19800e8SDoug Rabson 	return ASN1_BAD_FORMAT;
268c19800e8SDoug Rabson     data->length = len / 4;
269c19800e8SDoug Rabson     if (data->length > UINT_MAX/sizeof(data->data[0]))
270c19800e8SDoug Rabson 	return ERANGE;
271c19800e8SDoug Rabson     data->data = malloc(data->length * sizeof(data->data[0]));
272c19800e8SDoug Rabson     if (data->data == NULL && data->length != 0)
273c19800e8SDoug Rabson 	return ENOMEM;
274c19800e8SDoug Rabson 
275c19800e8SDoug Rabson     for (i = 0; i < data->length; i++) {
276c19800e8SDoug Rabson 	data->data[i] = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
277c19800e8SDoug Rabson 	p += 4;
278ae771770SStanislav Sedov 	/* check for NUL in the middle of the string */
279ae771770SStanislav Sedov 	if (data->data[i] == 0 && i != (data->length - 1)) {
280ae771770SStanislav Sedov 	    free(data->data);
281ae771770SStanislav Sedov 	    data->data = NULL;
282ae771770SStanislav Sedov 	    data->length = 0;
283ae771770SStanislav Sedov 	    return ASN1_BAD_CHARACTER;
284ae771770SStanislav Sedov 	}
285c19800e8SDoug Rabson     }
286c19800e8SDoug Rabson     if (size) *size = len;
287c19800e8SDoug Rabson     return 0;
288c19800e8SDoug Rabson }
289c19800e8SDoug Rabson 
290c19800e8SDoug Rabson int
291c19800e8SDoug Rabson der_get_visible_string (const unsigned char *p, size_t len,
292c19800e8SDoug Rabson 			heim_visible_string *str, size_t *size)
293c19800e8SDoug Rabson {
294c19800e8SDoug Rabson     return der_get_general_string(p, len, str, size);
295c19800e8SDoug Rabson }
296c19800e8SDoug Rabson 
297c19800e8SDoug Rabson int
298b528cefcSMark Murray der_get_octet_string (const unsigned char *p, size_t len,
299c19800e8SDoug Rabson 		      heim_octet_string *data, size_t *size)
300b528cefcSMark Murray {
301b528cefcSMark Murray     data->length = len;
302b528cefcSMark Murray     data->data = malloc(len);
303b528cefcSMark Murray     if (data->data == NULL && data->length != 0)
304b528cefcSMark Murray 	return ENOMEM;
305b528cefcSMark Murray     memcpy (data->data, p, len);
306b528cefcSMark Murray     if(size) *size = len;
307b528cefcSMark Murray     return 0;
308b528cefcSMark Murray }
309b528cefcSMark Murray 
310b528cefcSMark Murray int
311ae771770SStanislav Sedov der_get_octet_string_ber (const unsigned char *p, size_t len,
312ae771770SStanislav Sedov 			  heim_octet_string *data, size_t *size)
313ae771770SStanislav Sedov {
314ae771770SStanislav Sedov     int e;
315ae771770SStanislav Sedov     Der_type type;
316ae771770SStanislav Sedov     Der_class class;
317ae771770SStanislav Sedov     unsigned int tag, depth = 0;
318ae771770SStanislav Sedov     size_t l, datalen, oldlen = len;
319ae771770SStanislav Sedov 
320ae771770SStanislav Sedov     data->length = 0;
321ae771770SStanislav Sedov     data->data = NULL;
322ae771770SStanislav Sedov 
323ae771770SStanislav Sedov     while (len) {
324ae771770SStanislav Sedov 	e = der_get_tag (p, len, &class, &type, &tag, &l);
325ae771770SStanislav Sedov 	if (e) goto out;
326ae771770SStanislav Sedov 	if (class != ASN1_C_UNIV) {
327ae771770SStanislav Sedov 	    e = ASN1_BAD_ID;
328ae771770SStanislav Sedov 	    goto out;
329ae771770SStanislav Sedov 	}
330ae771770SStanislav Sedov 	if (type == PRIM && tag == UT_EndOfContent) {
331ae771770SStanislav Sedov 	    if (depth == 0)
332ae771770SStanislav Sedov 		break;
333ae771770SStanislav Sedov 	    depth--;
334ae771770SStanislav Sedov 	}
335ae771770SStanislav Sedov 	if (tag != UT_OctetString) {
336ae771770SStanislav Sedov 	    e = ASN1_BAD_ID;
337ae771770SStanislav Sedov 	    goto out;
338ae771770SStanislav Sedov 	}
339ae771770SStanislav Sedov 
340ae771770SStanislav Sedov 	p += l;
341ae771770SStanislav Sedov 	len -= l;
342ae771770SStanislav Sedov 	e = der_get_length (p, len, &datalen, &l);
343ae771770SStanislav Sedov 	if (e) goto out;
344ae771770SStanislav Sedov 	p += l;
345ae771770SStanislav Sedov 	len -= l;
346ae771770SStanislav Sedov 
347ae771770SStanislav Sedov 	if (datalen > len)
348ae771770SStanislav Sedov 	    return ASN1_OVERRUN;
349ae771770SStanislav Sedov 
350ae771770SStanislav Sedov 	if (type == PRIM) {
351ae771770SStanislav Sedov 	    void *ptr;
352ae771770SStanislav Sedov 
353ae771770SStanislav Sedov 	    ptr = realloc(data->data, data->length + datalen);
354ae771770SStanislav Sedov 	    if (ptr == NULL) {
355ae771770SStanislav Sedov 		e = ENOMEM;
356ae771770SStanislav Sedov 		goto out;
357ae771770SStanislav Sedov 	    }
358ae771770SStanislav Sedov 	    data->data = ptr;
359ae771770SStanislav Sedov 	    memcpy(((unsigned char *)data->data) + data->length, p, datalen);
360ae771770SStanislav Sedov 	    data->length += datalen;
361ae771770SStanislav Sedov 	} else
362ae771770SStanislav Sedov 	    depth++;
363ae771770SStanislav Sedov 
364ae771770SStanislav Sedov 	p += datalen;
365ae771770SStanislav Sedov 	len -= datalen;
366ae771770SStanislav Sedov     }
367ae771770SStanislav Sedov     if (depth != 0)
368ae771770SStanislav Sedov 	return ASN1_INDEF_OVERRUN;
369ae771770SStanislav Sedov     if(size) *size = oldlen - len;
370ae771770SStanislav Sedov     return 0;
371ae771770SStanislav Sedov  out:
372ae771770SStanislav Sedov     free(data->data);
373ae771770SStanislav Sedov     data->data = NULL;
374ae771770SStanislav Sedov     data->length = 0;
375ae771770SStanislav Sedov     return e;
376ae771770SStanislav Sedov }
377ae771770SStanislav Sedov 
378ae771770SStanislav Sedov 
379ae771770SStanislav Sedov int
380c19800e8SDoug Rabson der_get_heim_integer (const unsigned char *p, size_t len,
381c19800e8SDoug Rabson 		      heim_integer *data, size_t *size)
3824137ff4cSJacques Vidrine {
383c19800e8SDoug Rabson     data->length = 0;
384c19800e8SDoug Rabson     data->negative = 0;
385c19800e8SDoug Rabson     data->data = NULL;
386c19800e8SDoug Rabson 
387c19800e8SDoug Rabson     if (len == 0) {
388c19800e8SDoug Rabson 	if (size)
389c19800e8SDoug Rabson 	    *size = 0;
390c19800e8SDoug Rabson 	return 0;
391c19800e8SDoug Rabson     }
392c19800e8SDoug Rabson     if (p[0] & 0x80) {
393c19800e8SDoug Rabson 	unsigned char *q;
394c19800e8SDoug Rabson 	int carry = 1;
395c19800e8SDoug Rabson 	data->negative = 1;
396c19800e8SDoug Rabson 
397c19800e8SDoug Rabson 	data->length = len;
398c19800e8SDoug Rabson 
399c19800e8SDoug Rabson 	if (p[0] == 0xff) {
400c19800e8SDoug Rabson 	    p++;
401c19800e8SDoug Rabson 	    data->length--;
402c19800e8SDoug Rabson 	}
403c19800e8SDoug Rabson 	data->data = malloc(data->length);
404c19800e8SDoug Rabson 	if (data->data == NULL) {
405c19800e8SDoug Rabson 	    data->length = 0;
406c19800e8SDoug Rabson 	    if (size)
407c19800e8SDoug Rabson 		*size = 0;
408c19800e8SDoug Rabson 	    return ENOMEM;
409c19800e8SDoug Rabson 	}
410c19800e8SDoug Rabson 	q = &((unsigned char*)data->data)[data->length - 1];
411c19800e8SDoug Rabson 	p += data->length - 1;
412c19800e8SDoug Rabson 	while (q >= (unsigned char*)data->data) {
413c19800e8SDoug Rabson 	    *q = *p ^ 0xff;
414c19800e8SDoug Rabson 	    if (carry)
415c19800e8SDoug Rabson 		carry = !++*q;
416c19800e8SDoug Rabson 	    p--;
417c19800e8SDoug Rabson 	    q--;
418c19800e8SDoug Rabson 	}
419c19800e8SDoug Rabson     } else {
420c19800e8SDoug Rabson 	data->negative = 0;
421c19800e8SDoug Rabson 	data->length = len;
422c19800e8SDoug Rabson 
423c19800e8SDoug Rabson 	if (p[0] == 0) {
424c19800e8SDoug Rabson 	    p++;
425c19800e8SDoug Rabson 	    data->length--;
426c19800e8SDoug Rabson 	}
427c19800e8SDoug Rabson 	data->data = malloc(data->length);
428c19800e8SDoug Rabson 	if (data->data == NULL && data->length != 0) {
429c19800e8SDoug Rabson 	    data->length = 0;
430c19800e8SDoug Rabson 	    if (size)
431c19800e8SDoug Rabson 		*size = 0;
432c19800e8SDoug Rabson 	    return ENOMEM;
433c19800e8SDoug Rabson 	}
434c19800e8SDoug Rabson 	memcpy(data->data, p, data->length);
435c19800e8SDoug Rabson     }
436c19800e8SDoug Rabson     if (size)
437c19800e8SDoug Rabson 	*size = len;
438c19800e8SDoug Rabson     return 0;
439c19800e8SDoug Rabson }
440c19800e8SDoug Rabson 
441c19800e8SDoug Rabson static int
442c19800e8SDoug Rabson generalizedtime2time (const char *s, time_t *t)
443c19800e8SDoug Rabson {
444c19800e8SDoug Rabson     struct tm tm;
445c19800e8SDoug Rabson 
446c19800e8SDoug Rabson     memset(&tm, 0, sizeof(tm));
447c19800e8SDoug Rabson     if (sscanf (s, "%04d%02d%02d%02d%02d%02dZ",
448c19800e8SDoug Rabson 		&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
449c19800e8SDoug Rabson 		&tm.tm_min, &tm.tm_sec) != 6) {
450c19800e8SDoug Rabson 	if (sscanf (s, "%02d%02d%02d%02d%02d%02dZ",
451c19800e8SDoug Rabson 		    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
452c19800e8SDoug Rabson 		    &tm.tm_min, &tm.tm_sec) != 6)
453c19800e8SDoug Rabson 	    return ASN1_BAD_TIMEFORMAT;
454c19800e8SDoug Rabson 	if (tm.tm_year < 50)
455c19800e8SDoug Rabson 	    tm.tm_year += 2000;
456c19800e8SDoug Rabson 	else
457c19800e8SDoug Rabson 	    tm.tm_year += 1900;
458c19800e8SDoug Rabson     }
459c19800e8SDoug Rabson     tm.tm_year -= 1900;
460c19800e8SDoug Rabson     tm.tm_mon -= 1;
461c19800e8SDoug Rabson     *t = _der_timegm (&tm);
462c19800e8SDoug Rabson     return 0;
463c19800e8SDoug Rabson }
464c19800e8SDoug Rabson 
465c19800e8SDoug Rabson static int
466c19800e8SDoug Rabson der_get_time (const unsigned char *p, size_t len,
467c19800e8SDoug Rabson 	      time_t *data, size_t *size)
468c19800e8SDoug Rabson {
469c19800e8SDoug Rabson     char *times;
470c19800e8SDoug Rabson     int e;
471c19800e8SDoug Rabson 
472c19800e8SDoug Rabson     if (len > len + 1 || len == 0)
473c19800e8SDoug Rabson 	return ASN1_BAD_LENGTH;
474c19800e8SDoug Rabson 
475c19800e8SDoug Rabson     times = malloc(len + 1);
476c19800e8SDoug Rabson     if (times == NULL)
477c19800e8SDoug Rabson 	return ENOMEM;
478c19800e8SDoug Rabson     memcpy(times, p, len);
479c19800e8SDoug Rabson     times[len] = '\0';
480c19800e8SDoug Rabson     e = generalizedtime2time(times, data);
481c19800e8SDoug Rabson     free (times);
482c19800e8SDoug Rabson     if(size) *size = len;
483c19800e8SDoug Rabson     return e;
484c19800e8SDoug Rabson }
485c19800e8SDoug Rabson 
486c19800e8SDoug Rabson int
487c19800e8SDoug Rabson der_get_generalized_time (const unsigned char *p, size_t len,
488c19800e8SDoug Rabson 			  time_t *data, size_t *size)
489c19800e8SDoug Rabson {
490c19800e8SDoug Rabson     return der_get_time(p, len, data, size);
491c19800e8SDoug Rabson }
492c19800e8SDoug Rabson 
493c19800e8SDoug Rabson int
494c19800e8SDoug Rabson der_get_utctime (const unsigned char *p, size_t len,
495c19800e8SDoug Rabson 			  time_t *data, size_t *size)
496c19800e8SDoug Rabson {
497c19800e8SDoug Rabson     return der_get_time(p, len, data, size);
498c19800e8SDoug Rabson }
499c19800e8SDoug Rabson 
500c19800e8SDoug Rabson int
501c19800e8SDoug Rabson der_get_oid (const unsigned char *p, size_t len,
502c19800e8SDoug Rabson 	     heim_oid *data, size_t *size)
503c19800e8SDoug Rabson {
504c19800e8SDoug Rabson     size_t n;
5054137ff4cSJacques Vidrine     size_t oldlen = len;
5064137ff4cSJacques Vidrine 
5074137ff4cSJacques Vidrine     if (len < 1)
5084137ff4cSJacques Vidrine 	return ASN1_OVERRUN;
5094137ff4cSJacques Vidrine 
510c19800e8SDoug Rabson     if (len > len + 1)
511c19800e8SDoug Rabson 	return ASN1_BAD_LENGTH;
512c19800e8SDoug Rabson 
513c19800e8SDoug Rabson     if (len + 1 > UINT_MAX/sizeof(data->components[0]))
514c19800e8SDoug Rabson 	return ERANGE;
515c19800e8SDoug Rabson 
516c19800e8SDoug Rabson     data->components = malloc((len + 1) * sizeof(data->components[0]));
517c19800e8SDoug Rabson     if (data->components == NULL)
5184137ff4cSJacques Vidrine 	return ENOMEM;
5194137ff4cSJacques Vidrine     data->components[0] = (*p) / 40;
5204137ff4cSJacques Vidrine     data->components[1] = (*p) % 40;
5214137ff4cSJacques Vidrine     --len;
5224137ff4cSJacques Vidrine     ++p;
5234137ff4cSJacques Vidrine     for (n = 2; len > 0; ++n) {
524c19800e8SDoug Rabson 	unsigned u = 0, u1;
5254137ff4cSJacques Vidrine 
5264137ff4cSJacques Vidrine 	do {
5274137ff4cSJacques Vidrine 	    --len;
528c19800e8SDoug Rabson 	    u1 = u * 128 + (*p++ % 128);
529c19800e8SDoug Rabson 	    /* check that we don't overflow the element */
530c19800e8SDoug Rabson 	    if (u1 < u) {
531c19800e8SDoug Rabson 		der_free_oid(data);
532c19800e8SDoug Rabson 		return ASN1_OVERRUN;
533c19800e8SDoug Rabson 	    }
534c19800e8SDoug Rabson 	    u = u1;
5354137ff4cSJacques Vidrine 	} while (len > 0 && p[-1] & 0x80);
5364137ff4cSJacques Vidrine 	data->components[n] = u;
5374137ff4cSJacques Vidrine     }
538c19800e8SDoug Rabson     if (n > 2 && p[-1] & 0x80) {
539c19800e8SDoug Rabson 	der_free_oid (data);
5404137ff4cSJacques Vidrine 	return ASN1_OVERRUN;
5414137ff4cSJacques Vidrine     }
5424137ff4cSJacques Vidrine     data->length = n;
5434137ff4cSJacques Vidrine     if (size)
5444137ff4cSJacques Vidrine 	*size = oldlen;
5454137ff4cSJacques Vidrine     return 0;
5464137ff4cSJacques Vidrine }
5474137ff4cSJacques Vidrine 
5484137ff4cSJacques Vidrine int
549b528cefcSMark Murray der_get_tag (const unsigned char *p, size_t len,
550b528cefcSMark Murray 	     Der_class *class, Der_type *type,
551c19800e8SDoug Rabson 	     unsigned int *tag, size_t *size)
552b528cefcSMark Murray {
553c19800e8SDoug Rabson     size_t ret = 0;
554b528cefcSMark Murray     if (len < 1)
555b528cefcSMark Murray 	return ASN1_OVERRUN;
556b528cefcSMark Murray     *class = (Der_class)(((*p) >> 6) & 0x03);
557b528cefcSMark Murray     *type = (Der_type)(((*p) >> 5) & 0x01);
558c19800e8SDoug Rabson     *tag = (*p) & 0x1f;
559c19800e8SDoug Rabson     p++; len--; ret++;
560c19800e8SDoug Rabson     if(*tag == 0x1f) {
561c19800e8SDoug Rabson 	unsigned int continuation;
562c19800e8SDoug Rabson 	unsigned int tag1;
563c19800e8SDoug Rabson 	*tag = 0;
564c19800e8SDoug Rabson 	do {
565c19800e8SDoug Rabson 	    if(len < 1)
566c19800e8SDoug Rabson 		return ASN1_OVERRUN;
567c19800e8SDoug Rabson 	    continuation = *p & 128;
568c19800e8SDoug Rabson 	    tag1 = *tag * 128 + (*p % 128);
569c19800e8SDoug Rabson 	    /* check that we don't overflow the tag */
570c19800e8SDoug Rabson 	    if (tag1 < *tag)
571c19800e8SDoug Rabson 		return ASN1_OVERFLOW;
572c19800e8SDoug Rabson 	    *tag = tag1;
573c19800e8SDoug Rabson 	    p++; len--; ret++;
574c19800e8SDoug Rabson 	} while(continuation);
575c19800e8SDoug Rabson     }
576c19800e8SDoug Rabson     if(size) *size = ret;
577b528cefcSMark Murray     return 0;
578b528cefcSMark Murray }
579b528cefcSMark Murray 
580b528cefcSMark Murray int
581b528cefcSMark Murray der_match_tag (const unsigned char *p, size_t len,
582b528cefcSMark Murray 	       Der_class class, Der_type type,
583c19800e8SDoug Rabson 	       unsigned int tag, size_t *size)
584b528cefcSMark Murray {
585ae771770SStanislav Sedov     Der_type thistype;
586ae771770SStanislav Sedov     int e;
587ae771770SStanislav Sedov 
588ae771770SStanislav Sedov     e = der_match_tag2(p, len, class, &thistype, tag, size);
589ae771770SStanislav Sedov     if (e) return e;
590ae771770SStanislav Sedov     if (thistype != type) return ASN1_BAD_ID;
591ae771770SStanislav Sedov     return 0;
592ae771770SStanislav Sedov }
593ae771770SStanislav Sedov 
594ae771770SStanislav Sedov int
595ae771770SStanislav Sedov der_match_tag2 (const unsigned char *p, size_t len,
596ae771770SStanislav Sedov 		Der_class class, Der_type *type,
597ae771770SStanislav Sedov 		unsigned int tag, size_t *size)
598ae771770SStanislav Sedov {
599b528cefcSMark Murray     size_t l;
600b528cefcSMark Murray     Der_class thisclass;
601c19800e8SDoug Rabson     unsigned int thistag;
602b528cefcSMark Murray     int e;
603b528cefcSMark Murray 
604ae771770SStanislav Sedov     e = der_get_tag (p, len, &thisclass, type, &thistag, &l);
605b528cefcSMark Murray     if (e) return e;
606ae771770SStanislav Sedov     if (class != thisclass)
607b528cefcSMark Murray 	return ASN1_BAD_ID;
608b528cefcSMark Murray     if(tag > thistag)
609b528cefcSMark Murray 	return ASN1_MISPLACED_FIELD;
610b528cefcSMark Murray     if(tag < thistag)
611b528cefcSMark Murray 	return ASN1_MISSING_FIELD;
612b528cefcSMark Murray     if(size) *size = l;
613b528cefcSMark Murray     return 0;
614b528cefcSMark Murray }
615b528cefcSMark Murray 
616b528cefcSMark Murray int
617b528cefcSMark Murray der_match_tag_and_length (const unsigned char *p, size_t len,
618ae771770SStanislav Sedov 			  Der_class class, Der_type *type, unsigned int tag,
619b528cefcSMark Murray 			  size_t *length_ret, size_t *size)
620b528cefcSMark Murray {
621b528cefcSMark Murray     size_t l, ret = 0;
622b528cefcSMark Murray     int e;
623b528cefcSMark Murray 
624ae771770SStanislav Sedov     e = der_match_tag2 (p, len, class, type, tag, &l);
625b528cefcSMark Murray     if (e) return e;
626b528cefcSMark Murray     p += l;
627b528cefcSMark Murray     len -= l;
628b528cefcSMark Murray     ret += l;
629b528cefcSMark Murray     e = der_get_length (p, len, length_ret, &l);
630b528cefcSMark Murray     if (e) return e;
631ae771770SStanislav Sedov     if(size) *size = ret + l;
632b528cefcSMark Murray     return 0;
633b528cefcSMark Murray }
634b528cefcSMark Murray 
635ae771770SStanislav Sedov 
636ae771770SStanislav Sedov 
637c19800e8SDoug Rabson /*
638c19800e8SDoug Rabson  * Old versions of DCE was based on a very early beta of the MIT code,
639c19800e8SDoug Rabson  * which used MAVROS for ASN.1 encoding. MAVROS had the interesting
640c19800e8SDoug Rabson  * feature that it encoded data in the forward direction, which has
641c19800e8SDoug Rabson  * it's problems, since you have no idea how long the data will be
642c19800e8SDoug Rabson  * until after you're done. MAVROS solved this by reserving one byte
643c19800e8SDoug Rabson  * for length, and later, if the actual length was longer, it reverted
644c19800e8SDoug Rabson  * to indefinite, BER style, lengths. The version of MAVROS used by
645c19800e8SDoug Rabson  * the DCE people could apparently generate correct X.509 DER encodings, and
646c19800e8SDoug Rabson  * did this by making space for the length after encoding, but
647c19800e8SDoug Rabson  * unfortunately this feature wasn't used with Kerberos.
648c19800e8SDoug Rabson  */
649b528cefcSMark Murray 
650b528cefcSMark Murray int
651c19800e8SDoug Rabson _heim_fix_dce(size_t reallen, size_t *len)
652b528cefcSMark Murray {
653b528cefcSMark Murray     if(reallen == ASN1_INDEFINITE)
654b528cefcSMark Murray 	return 1;
655b528cefcSMark Murray     if(*len < reallen)
656b528cefcSMark Murray 	return -1;
657b528cefcSMark Murray     *len = reallen;
658b528cefcSMark Murray     return 0;
659b528cefcSMark Murray }
660c19800e8SDoug Rabson 
661c19800e8SDoug Rabson int
662c19800e8SDoug Rabson der_get_bit_string (const unsigned char *p, size_t len,
663c19800e8SDoug Rabson 		    heim_bit_string *data, size_t *size)
664c19800e8SDoug Rabson {
665c19800e8SDoug Rabson     if (len < 1)
666c19800e8SDoug Rabson 	return ASN1_OVERRUN;
667c19800e8SDoug Rabson     if (p[0] > 7)
668c19800e8SDoug Rabson 	return ASN1_BAD_FORMAT;
669c19800e8SDoug Rabson     if (len - 1 == 0 && p[0] != 0)
670c19800e8SDoug Rabson 	return ASN1_BAD_FORMAT;
671c19800e8SDoug Rabson     /* check if any of the three upper bits are set
672c19800e8SDoug Rabson      * any of them will cause a interger overrun */
673c19800e8SDoug Rabson     if ((len - 1) >> (sizeof(len) * 8 - 3))
674c19800e8SDoug Rabson 	return ASN1_OVERRUN;
675c19800e8SDoug Rabson     data->length = (len - 1) * 8;
676c19800e8SDoug Rabson     data->data = malloc(len - 1);
677c19800e8SDoug Rabson     if (data->data == NULL && (len - 1) != 0)
678c19800e8SDoug Rabson 	return ENOMEM;
679ae771770SStanislav Sedov     /* copy data is there is data to copy */
680ae771770SStanislav Sedov     if (len - 1 != 0) {
681c19800e8SDoug Rabson       memcpy (data->data, p + 1, len - 1);
682c19800e8SDoug Rabson       data->length -= p[0];
683ae771770SStanislav Sedov     }
684c19800e8SDoug Rabson     if(size) *size = len;
685c19800e8SDoug Rabson     return 0;
686c19800e8SDoug Rabson }
687