155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "der_locl.h"
3555682Smarkm
36233294Sstas/*
3755682Smarkm * All decoding functions take a pointer `p' to first position in
3855682Smarkm * which to read, from the left, `len' which means the maximum number
3955682Smarkm * of characters we are able to read, `ret' were the value will be
4055682Smarkm * returned and `size' where the number of used bytes is stored.
4155682Smarkm * Either 0 or an error code is returned.
4255682Smarkm */
4355682Smarkm
44178825Sdfrint
4555682Smarkmder_get_unsigned (const unsigned char *p, size_t len,
4655682Smarkm		  unsigned *ret, size_t *size)
4755682Smarkm{
4855682Smarkm    unsigned val = 0;
4955682Smarkm    size_t oldlen = len;
5055682Smarkm
51178825Sdfr    if (len == sizeof(unsigned) + 1 && p[0] == 0)
52178825Sdfr	;
53178825Sdfr    else if (len > sizeof(unsigned))
54178825Sdfr	return ASN1_OVERRUN;
55178825Sdfr
5655682Smarkm    while (len--)
5755682Smarkm	val = val * 256 + *p++;
5855682Smarkm    *ret = val;
5955682Smarkm    if(size) *size = oldlen;
6055682Smarkm    return 0;
6155682Smarkm}
6255682Smarkm
6355682Smarkmint
64178825Sdfrder_get_integer (const unsigned char *p, size_t len,
65178825Sdfr		 int *ret, size_t *size)
6655682Smarkm{
6755682Smarkm    int val = 0;
6855682Smarkm    size_t oldlen = len;
6955682Smarkm
70178825Sdfr    if (len > sizeof(int))
71178825Sdfr	return ASN1_OVERRUN;
72178825Sdfr
73102644Snectar    if (len > 0) {
7455682Smarkm	val = (signed char)*p++;
75102644Snectar	while (--len)
76102644Snectar	    val = val * 256 + *p++;
77102644Snectar    }
7855682Smarkm    *ret = val;
7955682Smarkm    if(size) *size = oldlen;
8055682Smarkm    return 0;
8155682Smarkm}
8255682Smarkm
8355682Smarkmint
8455682Smarkmder_get_length (const unsigned char *p, size_t len,
8555682Smarkm		size_t *val, size_t *size)
8655682Smarkm{
8755682Smarkm    size_t v;
8855682Smarkm
8955682Smarkm    if (len <= 0)
9055682Smarkm	return ASN1_OVERRUN;
9155682Smarkm    --len;
9255682Smarkm    v = *p++;
9355682Smarkm    if (v < 128) {
9455682Smarkm	*val = v;
9555682Smarkm	if(size) *size = 1;
9655682Smarkm    } else {
9755682Smarkm	int e;
9855682Smarkm	size_t l;
9955682Smarkm	unsigned tmp;
10055682Smarkm
10155682Smarkm	if(v == 0x80){
10255682Smarkm	    *val = ASN1_INDEFINITE;
10355682Smarkm	    if(size) *size = 1;
10455682Smarkm	    return 0;
10555682Smarkm	}
10655682Smarkm	v &= 0x7F;
10755682Smarkm	if (len < v)
10855682Smarkm	    return ASN1_OVERRUN;
10955682Smarkm	e = der_get_unsigned (p, v, &tmp, &l);
11055682Smarkm	if(e) return e;
11155682Smarkm	*val = tmp;
11255682Smarkm	if(size) *size = l + 1;
11355682Smarkm    }
11455682Smarkm    return 0;
11555682Smarkm}
11655682Smarkm
11755682Smarkmint
118178825Sdfrder_get_boolean(const unsigned char *p, size_t len, int *data, size_t *size)
119178825Sdfr{
120178825Sdfr    if(len < 1)
121178825Sdfr	return ASN1_OVERRUN;
122178825Sdfr    if(*p != 0)
123178825Sdfr	*data = 1;
124178825Sdfr    else
125178825Sdfr	*data = 0;
126178825Sdfr    *size = 1;
127178825Sdfr    return 0;
128178825Sdfr}
129178825Sdfr
130178825Sdfrint
131233294Sstasder_get_general_string (const unsigned char *p, size_t len,
132178825Sdfr			heim_general_string *str, size_t *size)
13355682Smarkm{
134178825Sdfr    const unsigned char *p1;
13555682Smarkm    char *s;
13655682Smarkm
137178825Sdfr    p1 = memchr(p, 0, len);
138178825Sdfr    if (p1 != NULL) {
139233294Sstas	/*
140178825Sdfr	 * Allow trailing NULs. We allow this since MIT Kerberos sends
141178825Sdfr	 * an strings in the NEED_PREAUTH case that includes a
142178825Sdfr	 * trailing NUL.
143178825Sdfr	 */
144233294Sstas	while ((size_t)(p1 - p) < len && *p1 == '\0')
145178825Sdfr	    p1++;
146233294Sstas       if ((size_t)(p1 - p) != len)
147178825Sdfr	    return ASN1_BAD_CHARACTER;
148178825Sdfr    }
149178825Sdfr    if (len > len + 1)
150178825Sdfr	return ASN1_BAD_LENGTH;
151178825Sdfr
15255682Smarkm    s = malloc (len + 1);
15355682Smarkm    if (s == NULL)
15455682Smarkm	return ENOMEM;
15555682Smarkm    memcpy (s, p, len);
15655682Smarkm    s[len] = '\0';
15755682Smarkm    *str = s;
15855682Smarkm    if(size) *size = len;
15955682Smarkm    return 0;
16055682Smarkm}
16155682Smarkm
16255682Smarkmint
163233294Sstasder_get_utf8string (const unsigned char *p, size_t len,
164178825Sdfr		    heim_utf8_string *str, size_t *size)
165178825Sdfr{
166178825Sdfr    return der_get_general_string(p, len, str, size);
167178825Sdfr}
168178825Sdfr
169178825Sdfrint
170233294Sstasder_get_printable_string(const unsigned char *p, size_t len,
171233294Sstas			 heim_printable_string *str, size_t *size)
172178825Sdfr{
173233294Sstas    str->length = len;
174233294Sstas    str->data = malloc(len + 1);
175233294Sstas    if (str->data == NULL)
176233294Sstas	return ENOMEM;
177233294Sstas    memcpy(str->data, p, len);
178233294Sstas    ((char *)str->data)[len] = '\0';
179233294Sstas    if(size) *size = len;
180233294Sstas    return 0;
181178825Sdfr}
182178825Sdfr
183178825Sdfrint
184233294Sstasder_get_ia5_string(const unsigned char *p, size_t len,
185233294Sstas		   heim_ia5_string *str, size_t *size)
186178825Sdfr{
187233294Sstas    return der_get_printable_string(p, len, str, size);
188178825Sdfr}
189178825Sdfr
190178825Sdfrint
191233294Sstasder_get_bmp_string (const unsigned char *p, size_t len,
192178825Sdfr		    heim_bmp_string *data, size_t *size)
193178825Sdfr{
194178825Sdfr    size_t i;
195178825Sdfr
196178825Sdfr    if (len & 1)
197178825Sdfr	return ASN1_BAD_FORMAT;
198178825Sdfr    data->length = len / 2;
199178825Sdfr    if (data->length > UINT_MAX/sizeof(data->data[0]))
200178825Sdfr	return ERANGE;
201178825Sdfr    data->data = malloc(data->length * sizeof(data->data[0]));
202178825Sdfr    if (data->data == NULL && data->length != 0)
203178825Sdfr	return ENOMEM;
204178825Sdfr
205178825Sdfr    for (i = 0; i < data->length; i++) {
206178825Sdfr	data->data[i] = (p[0] << 8) | p[1];
207178825Sdfr	p += 2;
208233294Sstas	/* check for NUL in the middle of the string */
209233294Sstas	if (data->data[i] == 0 && i != (data->length - 1)) {
210233294Sstas	    free(data->data);
211233294Sstas	    data->data = NULL;
212233294Sstas	    data->length = 0;
213233294Sstas	    return ASN1_BAD_CHARACTER;
214233294Sstas	}
215178825Sdfr    }
216178825Sdfr    if (size) *size = len;
217178825Sdfr
218178825Sdfr    return 0;
219178825Sdfr}
220178825Sdfr
221178825Sdfrint
222233294Sstasder_get_universal_string (const unsigned char *p, size_t len,
223178825Sdfr			  heim_universal_string *data, size_t *size)
224178825Sdfr{
225178825Sdfr    size_t i;
226178825Sdfr
227178825Sdfr    if (len & 3)
228178825Sdfr	return ASN1_BAD_FORMAT;
229178825Sdfr    data->length = len / 4;
230178825Sdfr    if (data->length > UINT_MAX/sizeof(data->data[0]))
231178825Sdfr	return ERANGE;
232178825Sdfr    data->data = malloc(data->length * sizeof(data->data[0]));
233178825Sdfr    if (data->data == NULL && data->length != 0)
234178825Sdfr	return ENOMEM;
235178825Sdfr
236178825Sdfr    for (i = 0; i < data->length; i++) {
237178825Sdfr	data->data[i] = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
238178825Sdfr	p += 4;
239233294Sstas	/* check for NUL in the middle of the string */
240233294Sstas	if (data->data[i] == 0 && i != (data->length - 1)) {
241233294Sstas	    free(data->data);
242233294Sstas	    data->data = NULL;
243233294Sstas	    data->length = 0;
244233294Sstas	    return ASN1_BAD_CHARACTER;
245233294Sstas	}
246178825Sdfr    }
247178825Sdfr    if (size) *size = len;
248178825Sdfr    return 0;
249178825Sdfr}
250178825Sdfr
251178825Sdfrint
252233294Sstasder_get_visible_string (const unsigned char *p, size_t len,
253178825Sdfr			heim_visible_string *str, size_t *size)
254178825Sdfr{
255178825Sdfr    return der_get_general_string(p, len, str, size);
256178825Sdfr}
257178825Sdfr
258178825Sdfrint
259233294Sstasder_get_octet_string (const unsigned char *p, size_t len,
260178825Sdfr		      heim_octet_string *data, size_t *size)
26155682Smarkm{
26255682Smarkm    data->length = len;
26355682Smarkm    data->data = malloc(len);
26455682Smarkm    if (data->data == NULL && data->length != 0)
26555682Smarkm	return ENOMEM;
26655682Smarkm    memcpy (data->data, p, len);
26755682Smarkm    if(size) *size = len;
26855682Smarkm    return 0;
26955682Smarkm}
27055682Smarkm
27155682Smarkmint
272233294Sstasder_get_octet_string_ber (const unsigned char *p, size_t len,
273233294Sstas			  heim_octet_string *data, size_t *size)
274233294Sstas{
275233294Sstas    int e;
276233294Sstas    Der_type type;
277233294Sstas    Der_class class;
278233294Sstas    unsigned int tag, depth = 0;
279233294Sstas    size_t l, datalen, oldlen = len;
280233294Sstas
281233294Sstas    data->length = 0;
282233294Sstas    data->data = NULL;
283233294Sstas
284233294Sstas    while (len) {
285233294Sstas	e = der_get_tag (p, len, &class, &type, &tag, &l);
286233294Sstas	if (e) goto out;
287233294Sstas	if (class != ASN1_C_UNIV) {
288233294Sstas	    e = ASN1_BAD_ID;
289233294Sstas	    goto out;
290233294Sstas	}
291233294Sstas	if (type == PRIM && tag == UT_EndOfContent) {
292233294Sstas	    if (depth == 0)
293233294Sstas		break;
294233294Sstas	    depth--;
295233294Sstas	}
296233294Sstas	if (tag != UT_OctetString) {
297233294Sstas	    e = ASN1_BAD_ID;
298233294Sstas	    goto out;
299233294Sstas	}
300233294Sstas
301233294Sstas	p += l;
302233294Sstas	len -= l;
303233294Sstas	e = der_get_length (p, len, &datalen, &l);
304233294Sstas	if (e) goto out;
305233294Sstas	p += l;
306233294Sstas	len -= l;
307233294Sstas
308233294Sstas	if (datalen > len)
309233294Sstas	    return ASN1_OVERRUN;
310233294Sstas
311233294Sstas	if (type == PRIM) {
312233294Sstas	    void *ptr;
313233294Sstas
314233294Sstas	    ptr = realloc(data->data, data->length + datalen);
315233294Sstas	    if (ptr == NULL) {
316233294Sstas		e = ENOMEM;
317233294Sstas		goto out;
318233294Sstas	    }
319233294Sstas	    data->data = ptr;
320233294Sstas	    memcpy(((unsigned char *)data->data) + data->length, p, datalen);
321233294Sstas	    data->length += datalen;
322233294Sstas	} else
323233294Sstas	    depth++;
324233294Sstas
325233294Sstas	p += datalen;
326233294Sstas	len -= datalen;
327233294Sstas    }
328233294Sstas    if (depth != 0)
329233294Sstas	return ASN1_INDEF_OVERRUN;
330233294Sstas    if(size) *size = oldlen - len;
331233294Sstas    return 0;
332233294Sstas out:
333233294Sstas    free(data->data);
334233294Sstas    data->data = NULL;
335233294Sstas    data->length = 0;
336233294Sstas    return e;
337233294Sstas}
338233294Sstas
339233294Sstas
340233294Sstasint
341233294Sstasder_get_heim_integer (const unsigned char *p, size_t len,
342178825Sdfr		      heim_integer *data, size_t *size)
343178825Sdfr{
344178825Sdfr    data->length = 0;
345178825Sdfr    data->negative = 0;
346178825Sdfr    data->data = NULL;
347178825Sdfr
348178825Sdfr    if (len == 0) {
349178825Sdfr	if (size)
350178825Sdfr	    *size = 0;
351178825Sdfr	return 0;
352178825Sdfr    }
353178825Sdfr    if (p[0] & 0x80) {
354178825Sdfr	unsigned char *q;
355178825Sdfr	int carry = 1;
356178825Sdfr	data->negative = 1;
357178825Sdfr
358178825Sdfr	data->length = len;
359178825Sdfr
360178825Sdfr	if (p[0] == 0xff) {
361178825Sdfr	    p++;
362178825Sdfr	    data->length--;
363178825Sdfr	}
364178825Sdfr	data->data = malloc(data->length);
365178825Sdfr	if (data->data == NULL) {
366178825Sdfr	    data->length = 0;
367178825Sdfr	    if (size)
368178825Sdfr		*size = 0;
369178825Sdfr	    return ENOMEM;
370178825Sdfr	}
371178825Sdfr	q = &((unsigned char*)data->data)[data->length - 1];
372178825Sdfr	p += data->length - 1;
373178825Sdfr	while (q >= (unsigned char*)data->data) {
374178825Sdfr	    *q = *p ^ 0xff;
375178825Sdfr	    if (carry)
376178825Sdfr		carry = !++*q;
377178825Sdfr	    p--;
378178825Sdfr	    q--;
379178825Sdfr	}
380178825Sdfr    } else {
381178825Sdfr	data->negative = 0;
382178825Sdfr	data->length = len;
383178825Sdfr
384178825Sdfr	if (p[0] == 0) {
385178825Sdfr	    p++;
386178825Sdfr	    data->length--;
387178825Sdfr	}
388178825Sdfr	data->data = malloc(data->length);
389178825Sdfr	if (data->data == NULL && data->length != 0) {
390178825Sdfr	    data->length = 0;
391178825Sdfr	    if (size)
392178825Sdfr		*size = 0;
393178825Sdfr	    return ENOMEM;
394178825Sdfr	}
395178825Sdfr	memcpy(data->data, p, data->length);
396178825Sdfr    }
397178825Sdfr    if (size)
398178825Sdfr	*size = len;
399178825Sdfr    return 0;
400178825Sdfr}
401178825Sdfr
402178825Sdfrstatic int
403178825Sdfrgeneralizedtime2time (const char *s, time_t *t)
404178825Sdfr{
405178825Sdfr    struct tm tm;
406178825Sdfr
407178825Sdfr    memset(&tm, 0, sizeof(tm));
408178825Sdfr    if (sscanf (s, "%04d%02d%02d%02d%02d%02dZ",
409178825Sdfr		&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
410178825Sdfr		&tm.tm_min, &tm.tm_sec) != 6) {
411178825Sdfr	if (sscanf (s, "%02d%02d%02d%02d%02d%02dZ",
412178825Sdfr		    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
413178825Sdfr		    &tm.tm_min, &tm.tm_sec) != 6)
414178825Sdfr	    return ASN1_BAD_TIMEFORMAT;
415178825Sdfr	if (tm.tm_year < 50)
416178825Sdfr	    tm.tm_year += 2000;
417178825Sdfr	else
418178825Sdfr	    tm.tm_year += 1900;
419178825Sdfr    }
420178825Sdfr    tm.tm_year -= 1900;
421178825Sdfr    tm.tm_mon -= 1;
422178825Sdfr    *t = _der_timegm (&tm);
423178825Sdfr    return 0;
424178825Sdfr}
425178825Sdfr
426178825Sdfrstatic int
427233294Sstasder_get_time (const unsigned char *p, size_t len,
428178825Sdfr	      time_t *data, size_t *size)
429178825Sdfr{
430178825Sdfr    char *times;
431178825Sdfr    int e;
432178825Sdfr
433178825Sdfr    if (len > len + 1 || len == 0)
434178825Sdfr	return ASN1_BAD_LENGTH;
435178825Sdfr
436178825Sdfr    times = malloc(len + 1);
437178825Sdfr    if (times == NULL)
438178825Sdfr	return ENOMEM;
439178825Sdfr    memcpy(times, p, len);
440178825Sdfr    times[len] = '\0';
441178825Sdfr    e = generalizedtime2time(times, data);
442178825Sdfr    free (times);
443178825Sdfr    if(size) *size = len;
444178825Sdfr    return e;
445178825Sdfr}
446178825Sdfr
447178825Sdfrint
448233294Sstasder_get_generalized_time (const unsigned char *p, size_t len,
449178825Sdfr			  time_t *data, size_t *size)
450178825Sdfr{
451178825Sdfr    return der_get_time(p, len, data, size);
452178825Sdfr}
453178825Sdfr
454178825Sdfrint
455233294Sstasder_get_utctime (const unsigned char *p, size_t len,
456178825Sdfr			  time_t *data, size_t *size)
457178825Sdfr{
458178825Sdfr    return der_get_time(p, len, data, size);
459178825Sdfr}
460178825Sdfr
461178825Sdfrint
46290926Snectarder_get_oid (const unsigned char *p, size_t len,
463178825Sdfr	     heim_oid *data, size_t *size)
46490926Snectar{
465178825Sdfr    size_t n;
46690926Snectar    size_t oldlen = len;
46790926Snectar
46890926Snectar    if (len < 1)
46990926Snectar	return ASN1_OVERRUN;
47090926Snectar
471178825Sdfr    if (len > len + 1)
472178825Sdfr	return ASN1_BAD_LENGTH;
473178825Sdfr
474178825Sdfr    if (len + 1 > UINT_MAX/sizeof(data->components[0]))
475178825Sdfr	return ERANGE;
476178825Sdfr
477178825Sdfr    data->components = malloc((len + 1) * sizeof(data->components[0]));
478178825Sdfr    if (data->components == NULL)
47990926Snectar	return ENOMEM;
48090926Snectar    data->components[0] = (*p) / 40;
48190926Snectar    data->components[1] = (*p) % 40;
48290926Snectar    --len;
48390926Snectar    ++p;
48490926Snectar    for (n = 2; len > 0; ++n) {
485178825Sdfr	unsigned u = 0, u1;
486233294Sstas
48790926Snectar	do {
48890926Snectar	    --len;
489178825Sdfr	    u1 = u * 128 + (*p++ % 128);
490178825Sdfr	    /* check that we don't overflow the element */
491178825Sdfr	    if (u1 < u) {
492178825Sdfr		der_free_oid(data);
493178825Sdfr		return ASN1_OVERRUN;
494178825Sdfr	    }
495178825Sdfr	    u = u1;
49690926Snectar	} while (len > 0 && p[-1] & 0x80);
49790926Snectar	data->components[n] = u;
49890926Snectar    }
499178825Sdfr    if (n > 2 && p[-1] & 0x80) {
500178825Sdfr	der_free_oid (data);
50190926Snectar	return ASN1_OVERRUN;
50290926Snectar    }
50390926Snectar    data->length = n;
50490926Snectar    if (size)
50590926Snectar	*size = oldlen;
50690926Snectar    return 0;
50790926Snectar}
50890926Snectar
50990926Snectarint
51055682Smarkmder_get_tag (const unsigned char *p, size_t len,
51155682Smarkm	     Der_class *class, Der_type *type,
512178825Sdfr	     unsigned int *tag, size_t *size)
51355682Smarkm{
514178825Sdfr    size_t ret = 0;
51555682Smarkm    if (len < 1)
51655682Smarkm	return ASN1_OVERRUN;
51755682Smarkm    *class = (Der_class)(((*p) >> 6) & 0x03);
51855682Smarkm    *type = (Der_type)(((*p) >> 5) & 0x01);
519178825Sdfr    *tag = (*p) & 0x1f;
520178825Sdfr    p++; len--; ret++;
521178825Sdfr    if(*tag == 0x1f) {
522178825Sdfr	unsigned int continuation;
523178825Sdfr	unsigned int tag1;
524178825Sdfr	*tag = 0;
525178825Sdfr	do {
526178825Sdfr	    if(len < 1)
527178825Sdfr		return ASN1_OVERRUN;
528178825Sdfr	    continuation = *p & 128;
529178825Sdfr	    tag1 = *tag * 128 + (*p % 128);
530178825Sdfr	    /* check that we don't overflow the tag */
531178825Sdfr	    if (tag1 < *tag)
532178825Sdfr		return ASN1_OVERFLOW;
533178825Sdfr	    *tag = tag1;
534178825Sdfr	    p++; len--; ret++;
535178825Sdfr	} while(continuation);
536178825Sdfr    }
537178825Sdfr    if(size) *size = ret;
53855682Smarkm    return 0;
53955682Smarkm}
54055682Smarkm
54155682Smarkmint
54255682Smarkmder_match_tag (const unsigned char *p, size_t len,
54355682Smarkm	       Der_class class, Der_type type,
544178825Sdfr	       unsigned int tag, size_t *size)
54555682Smarkm{
546233294Sstas    Der_type thistype;
547233294Sstas    int e;
548233294Sstas
549233294Sstas    e = der_match_tag2(p, len, class, &thistype, tag, size);
550233294Sstas    if (e) return e;
551233294Sstas    if (thistype != type) return ASN1_BAD_ID;
552233294Sstas    return 0;
553233294Sstas}
554233294Sstas
555233294Sstasint
556233294Sstasder_match_tag2 (const unsigned char *p, size_t len,
557233294Sstas		Der_class class, Der_type *type,
558233294Sstas		unsigned int tag, size_t *size)
559233294Sstas{
56055682Smarkm    size_t l;
56155682Smarkm    Der_class thisclass;
562178825Sdfr    unsigned int thistag;
56355682Smarkm    int e;
56455682Smarkm
565233294Sstas    e = der_get_tag (p, len, &thisclass, type, &thistag, &l);
56655682Smarkm    if (e) return e;
567233294Sstas    if (class != thisclass)
56855682Smarkm	return ASN1_BAD_ID;
56955682Smarkm    if(tag > thistag)
57055682Smarkm	return ASN1_MISPLACED_FIELD;
57155682Smarkm    if(tag < thistag)
57255682Smarkm	return ASN1_MISSING_FIELD;
57355682Smarkm    if(size) *size = l;
57455682Smarkm    return 0;
57555682Smarkm}
57655682Smarkm
57755682Smarkmint
57855682Smarkmder_match_tag_and_length (const unsigned char *p, size_t len,
579233294Sstas			  Der_class class, Der_type *type, unsigned int tag,
58055682Smarkm			  size_t *length_ret, size_t *size)
58155682Smarkm{
58255682Smarkm    size_t l, ret = 0;
58355682Smarkm    int e;
58455682Smarkm
585233294Sstas    e = der_match_tag2 (p, len, class, type, tag, &l);
58655682Smarkm    if (e) return e;
58755682Smarkm    p += l;
58855682Smarkm    len -= l;
58955682Smarkm    ret += l;
59055682Smarkm    e = der_get_length (p, len, length_ret, &l);
59155682Smarkm    if (e) return e;
592233294Sstas    if(size) *size = ret + l;
59355682Smarkm    return 0;
59455682Smarkm}
59555682Smarkm
596233294Sstas
597233294Sstas
598233294Sstas/*
599178825Sdfr * Old versions of DCE was based on a very early beta of the MIT code,
600178825Sdfr * which used MAVROS for ASN.1 encoding. MAVROS had the interesting
601178825Sdfr * feature that it encoded data in the forward direction, which has
602178825Sdfr * it's problems, since you have no idea how long the data will be
603178825Sdfr * until after you're done. MAVROS solved this by reserving one byte
604178825Sdfr * for length, and later, if the actual length was longer, it reverted
605178825Sdfr * to indefinite, BER style, lengths. The version of MAVROS used by
606178825Sdfr * the DCE people could apparently generate correct X.509 DER encodings, and
607178825Sdfr * did this by making space for the length after encoding, but
608233294Sstas * unfortunately this feature wasn't used with Kerberos.
609178825Sdfr */
61055682Smarkm
61155682Smarkmint
612178825Sdfr_heim_fix_dce(size_t reallen, size_t *len)
61372445Sassar{
614178825Sdfr    if(reallen == ASN1_INDEFINITE)
615178825Sdfr	return 1;
616178825Sdfr    if(*len < reallen)
617178825Sdfr	return -1;
618178825Sdfr    *len = reallen;
61972445Sassar    return 0;
62072445Sassar}
62172445Sassar
62272445Sassarint
623233294Sstasder_get_bit_string (const unsigned char *p, size_t len,
624178825Sdfr		    heim_bit_string *data, size_t *size)
62590926Snectar{
626178825Sdfr    if (len < 1)
62755682Smarkm	return ASN1_OVERRUN;
628178825Sdfr    if (p[0] > 7)
629178825Sdfr	return ASN1_BAD_FORMAT;
630178825Sdfr    if (len - 1 == 0 && p[0] != 0)
631178825Sdfr	return ASN1_BAD_FORMAT;
632178825Sdfr    /* check if any of the three upper bits are set
633178825Sdfr     * any of them will cause a interger overrun */
634178825Sdfr    if ((len - 1) >> (sizeof(len) * 8 - 3))
63555682Smarkm	return ASN1_OVERRUN;
636178825Sdfr    data->length = (len - 1) * 8;
637178825Sdfr    data->data = malloc(len - 1);
638178825Sdfr    if (data->data == NULL && (len - 1) != 0)
63955682Smarkm	return ENOMEM;
640233294Sstas    /* copy data is there is data to copy */
641233294Sstas    if (len - 1 != 0) {
642233294Sstas      memcpy (data->data, p + 1, len - 1);
643233294Sstas      data->length -= p[0];
644233294Sstas    }
645178825Sdfr    if(size) *size = len;
64655682Smarkm    return 0;
64755682Smarkm}
648