xref: /freebsd/crypto/heimdal/lib/asn1/der_get.c (revision 8373020d34ceb1ac55d8f43333c1ca3680185b39)
1b528cefcSMark Murray /*
28373020dSJacques Vidrine  * Copyright (c) 1997 - 2002 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 
368373020dSJacques Vidrine RCSID("$Id: der_get.c,v 1.32 2002/08/22 19:11:07 assar Exp $");
37b528cefcSMark Murray 
38b528cefcSMark Murray #include <version.h>
39b528cefcSMark Murray 
40b528cefcSMark Murray /*
41b528cefcSMark Murray  * All decoding functions take a pointer `p' to first position in
42b528cefcSMark Murray  * which to read, from the left, `len' which means the maximum number
43b528cefcSMark Murray  * of characters we are able to read, `ret' were the value will be
44b528cefcSMark Murray  * returned and `size' where the number of used bytes is stored.
45b528cefcSMark Murray  * Either 0 or an error code is returned.
46b528cefcSMark Murray  */
47b528cefcSMark Murray 
48b528cefcSMark Murray static int
49b528cefcSMark Murray der_get_unsigned (const unsigned char *p, size_t len,
50b528cefcSMark Murray 		  unsigned *ret, size_t *size)
51b528cefcSMark Murray {
52b528cefcSMark Murray     unsigned val = 0;
53b528cefcSMark Murray     size_t oldlen = len;
54b528cefcSMark Murray 
55b528cefcSMark Murray     while (len--)
56b528cefcSMark Murray 	val = val * 256 + *p++;
57b528cefcSMark Murray     *ret = val;
58b528cefcSMark Murray     if(size) *size = oldlen;
59b528cefcSMark Murray     return 0;
60b528cefcSMark Murray }
61b528cefcSMark Murray 
62b528cefcSMark Murray int
63b528cefcSMark Murray der_get_int (const unsigned char *p, size_t len,
64b528cefcSMark Murray 	     int *ret, size_t *size)
65b528cefcSMark Murray {
66b528cefcSMark Murray     int val = 0;
67b528cefcSMark Murray     size_t oldlen = len;
68b528cefcSMark Murray 
698373020dSJacques Vidrine     if (len > 0) {
70b528cefcSMark Murray 	val = (signed char)*p++;
718373020dSJacques Vidrine 	while (--len)
72b528cefcSMark Murray 	    val = val * 256 + *p++;
738373020dSJacques Vidrine     }
74b528cefcSMark Murray     *ret = val;
75b528cefcSMark Murray     if(size) *size = oldlen;
76b528cefcSMark Murray     return 0;
77b528cefcSMark Murray }
78b528cefcSMark Murray 
79b528cefcSMark Murray int
80b528cefcSMark Murray der_get_length (const unsigned char *p, size_t len,
81b528cefcSMark Murray 		size_t *val, size_t *size)
82b528cefcSMark Murray {
83b528cefcSMark Murray     size_t v;
84b528cefcSMark Murray 
85b528cefcSMark Murray     if (len <= 0)
86b528cefcSMark Murray 	return ASN1_OVERRUN;
87b528cefcSMark Murray     --len;
88b528cefcSMark Murray     v = *p++;
89b528cefcSMark Murray     if (v < 128) {
90b528cefcSMark Murray 	*val = v;
91b528cefcSMark Murray 	if(size) *size = 1;
92b528cefcSMark Murray     } else {
93b528cefcSMark Murray 	int e;
94b528cefcSMark Murray 	size_t l;
95b528cefcSMark Murray 	unsigned tmp;
96b528cefcSMark Murray 
97b528cefcSMark Murray 	if(v == 0x80){
98b528cefcSMark Murray 	    *val = ASN1_INDEFINITE;
99b528cefcSMark Murray 	    if(size) *size = 1;
100b528cefcSMark Murray 	    return 0;
101b528cefcSMark Murray 	}
102b528cefcSMark Murray 	v &= 0x7F;
103b528cefcSMark Murray 	if (len < v)
104b528cefcSMark Murray 	    return ASN1_OVERRUN;
105b528cefcSMark Murray 	e = der_get_unsigned (p, v, &tmp, &l);
106b528cefcSMark Murray 	if(e) return e;
107b528cefcSMark Murray 	*val = tmp;
108b528cefcSMark Murray 	if(size) *size = l + 1;
109b528cefcSMark Murray     }
110b528cefcSMark Murray     return 0;
111b528cefcSMark Murray }
112b528cefcSMark Murray 
113b528cefcSMark Murray int
114b528cefcSMark Murray der_get_general_string (const unsigned char *p, size_t len,
115b528cefcSMark Murray 			general_string *str, size_t *size)
116b528cefcSMark Murray {
117b528cefcSMark Murray     char *s;
118b528cefcSMark Murray 
119b528cefcSMark Murray     s = malloc (len + 1);
120b528cefcSMark Murray     if (s == NULL)
121b528cefcSMark Murray 	return ENOMEM;
122b528cefcSMark Murray     memcpy (s, p, len);
123b528cefcSMark Murray     s[len] = '\0';
124b528cefcSMark Murray     *str = s;
125b528cefcSMark Murray     if(size) *size = len;
126b528cefcSMark Murray     return 0;
127b528cefcSMark Murray }
128b528cefcSMark Murray 
129b528cefcSMark Murray int
130b528cefcSMark Murray der_get_octet_string (const unsigned char *p, size_t len,
131b528cefcSMark Murray 		      octet_string *data, size_t *size)
132b528cefcSMark Murray {
133b528cefcSMark Murray     data->length = len;
134b528cefcSMark Murray     data->data = malloc(len);
135b528cefcSMark Murray     if (data->data == NULL && data->length != 0)
136b528cefcSMark Murray 	return ENOMEM;
137b528cefcSMark Murray     memcpy (data->data, p, len);
138b528cefcSMark Murray     if(size) *size = len;
139b528cefcSMark Murray     return 0;
140b528cefcSMark Murray }
141b528cefcSMark Murray 
142b528cefcSMark Murray int
1434137ff4cSJacques Vidrine der_get_oid (const unsigned char *p, size_t len,
1444137ff4cSJacques Vidrine 	     oid *data, size_t *size)
1454137ff4cSJacques Vidrine {
1464137ff4cSJacques Vidrine     int n;
1474137ff4cSJacques Vidrine     size_t oldlen = len;
1484137ff4cSJacques Vidrine 
1494137ff4cSJacques Vidrine     if (len < 1)
1504137ff4cSJacques Vidrine 	return ASN1_OVERRUN;
1514137ff4cSJacques Vidrine 
1524137ff4cSJacques Vidrine     data->components = malloc(len * sizeof(*data->components));
1534137ff4cSJacques Vidrine     if (data->components == NULL && len != 0)
1544137ff4cSJacques Vidrine 	return ENOMEM;
1554137ff4cSJacques Vidrine     data->components[0] = (*p) / 40;
1564137ff4cSJacques Vidrine     data->components[1] = (*p) % 40;
1574137ff4cSJacques Vidrine     --len;
1584137ff4cSJacques Vidrine     ++p;
1594137ff4cSJacques Vidrine     for (n = 2; len > 0; ++n) {
1604137ff4cSJacques Vidrine 	unsigned u = 0;
1614137ff4cSJacques Vidrine 
1624137ff4cSJacques Vidrine 	do {
1634137ff4cSJacques Vidrine 	    --len;
1644137ff4cSJacques Vidrine 	    u = u * 128 + (*p++ % 128);
1654137ff4cSJacques Vidrine 	} while (len > 0 && p[-1] & 0x80);
1664137ff4cSJacques Vidrine 	data->components[n] = u;
1674137ff4cSJacques Vidrine     }
1684137ff4cSJacques Vidrine     if (p[-1] & 0x80) {
1694137ff4cSJacques Vidrine 	free_oid (data);
1704137ff4cSJacques Vidrine 	return ASN1_OVERRUN;
1714137ff4cSJacques Vidrine     }
1724137ff4cSJacques Vidrine     data->length = n;
1734137ff4cSJacques Vidrine     if (size)
1744137ff4cSJacques Vidrine 	*size = oldlen;
1754137ff4cSJacques Vidrine     return 0;
1764137ff4cSJacques Vidrine }
1774137ff4cSJacques Vidrine 
1784137ff4cSJacques Vidrine int
179b528cefcSMark Murray der_get_tag (const unsigned char *p, size_t len,
180b528cefcSMark Murray 	     Der_class *class, Der_type *type,
181b528cefcSMark Murray 	     int *tag, size_t *size)
182b528cefcSMark Murray {
183b528cefcSMark Murray     if (len < 1)
184b528cefcSMark Murray 	return ASN1_OVERRUN;
185b528cefcSMark Murray     *class = (Der_class)(((*p) >> 6) & 0x03);
186b528cefcSMark Murray     *type = (Der_type)(((*p) >> 5) & 0x01);
187b528cefcSMark Murray     *tag = (*p) & 0x1F;
188b528cefcSMark Murray     if(size) *size = 1;
189b528cefcSMark Murray     return 0;
190b528cefcSMark Murray }
191b528cefcSMark Murray 
192b528cefcSMark Murray int
193b528cefcSMark Murray der_match_tag (const unsigned char *p, size_t len,
194b528cefcSMark Murray 	       Der_class class, Der_type type,
195b528cefcSMark Murray 	       int tag, size_t *size)
196b528cefcSMark Murray {
197b528cefcSMark Murray     size_t l;
198b528cefcSMark Murray     Der_class thisclass;
199b528cefcSMark Murray     Der_type thistype;
200b528cefcSMark Murray     int thistag;
201b528cefcSMark Murray     int e;
202b528cefcSMark Murray 
203b528cefcSMark Murray     e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l);
204b528cefcSMark Murray     if (e) return e;
205b528cefcSMark Murray     if (class != thisclass || type != thistype)
206b528cefcSMark Murray 	return ASN1_BAD_ID;
207b528cefcSMark Murray     if(tag > thistag)
208b528cefcSMark Murray 	return ASN1_MISPLACED_FIELD;
209b528cefcSMark Murray     if(tag < thistag)
210b528cefcSMark Murray 	return ASN1_MISSING_FIELD;
211b528cefcSMark Murray     if(size) *size = l;
212b528cefcSMark Murray     return 0;
213b528cefcSMark Murray }
214b528cefcSMark Murray 
215b528cefcSMark Murray int
216b528cefcSMark Murray der_match_tag_and_length (const unsigned char *p, size_t len,
217b528cefcSMark Murray 			  Der_class class, Der_type type, int tag,
218b528cefcSMark Murray 			  size_t *length_ret, size_t *size)
219b528cefcSMark Murray {
220b528cefcSMark Murray     size_t l, ret = 0;
221b528cefcSMark Murray     int e;
222b528cefcSMark Murray 
223b528cefcSMark Murray     e = der_match_tag (p, len, class, type, tag, &l);
224b528cefcSMark Murray     if (e) return e;
225b528cefcSMark Murray     p += l;
226b528cefcSMark Murray     len -= l;
227b528cefcSMark Murray     ret += l;
228b528cefcSMark Murray     e = der_get_length (p, len, length_ret, &l);
229b528cefcSMark Murray     if (e) return e;
230b528cefcSMark Murray     p += l;
231b528cefcSMark Murray     len -= l;
232b528cefcSMark Murray     ret += l;
233b528cefcSMark Murray     if(size) *size = ret;
234b528cefcSMark Murray     return 0;
235b528cefcSMark Murray }
236b528cefcSMark Murray 
237b528cefcSMark Murray int
238b528cefcSMark Murray decode_integer (const unsigned char *p, size_t len,
239b528cefcSMark Murray 		int *num, size_t *size)
240b528cefcSMark Murray {
241b528cefcSMark Murray     size_t ret = 0;
242b528cefcSMark Murray     size_t l, reallen;
243b528cefcSMark Murray     int e;
244b528cefcSMark Murray 
245b528cefcSMark Murray     e = der_match_tag (p, len, UNIV, PRIM, UT_Integer, &l);
246b528cefcSMark Murray     if (e) return e;
247b528cefcSMark Murray     p += l;
248b528cefcSMark Murray     len -= l;
249b528cefcSMark Murray     ret += l;
250b528cefcSMark Murray     e = der_get_length (p, len, &reallen, &l);
251b528cefcSMark Murray     if (e) return e;
252b528cefcSMark Murray     p += l;
253b528cefcSMark Murray     len -= l;
254b528cefcSMark Murray     ret += l;
255b528cefcSMark Murray     e = der_get_int (p, reallen, num, &l);
256b528cefcSMark Murray     if (e) return e;
257b528cefcSMark Murray     p += l;
258b528cefcSMark Murray     len -= l;
259b528cefcSMark Murray     ret += l;
260b528cefcSMark Murray     if(size) *size = ret;
261b528cefcSMark Murray     return 0;
262b528cefcSMark Murray }
263b528cefcSMark Murray 
264b528cefcSMark Murray int
2655e9cd1aeSAssar Westerlund decode_unsigned (const unsigned char *p, size_t len,
2665e9cd1aeSAssar Westerlund 		 unsigned *num, size_t *size)
2675e9cd1aeSAssar Westerlund {
2685e9cd1aeSAssar Westerlund     size_t ret = 0;
2695e9cd1aeSAssar Westerlund     size_t l, reallen;
2705e9cd1aeSAssar Westerlund     int e;
2715e9cd1aeSAssar Westerlund 
2725e9cd1aeSAssar Westerlund     e = der_match_tag (p, len, UNIV, PRIM, UT_Integer, &l);
2735e9cd1aeSAssar Westerlund     if (e) return e;
2745e9cd1aeSAssar Westerlund     p += l;
2755e9cd1aeSAssar Westerlund     len -= l;
2765e9cd1aeSAssar Westerlund     ret += l;
2775e9cd1aeSAssar Westerlund     e = der_get_length (p, len, &reallen, &l);
2785e9cd1aeSAssar Westerlund     if (e) return e;
2795e9cd1aeSAssar Westerlund     p += l;
2805e9cd1aeSAssar Westerlund     len -= l;
2815e9cd1aeSAssar Westerlund     ret += l;
2825e9cd1aeSAssar Westerlund     e = der_get_unsigned (p, reallen, num, &l);
2835e9cd1aeSAssar Westerlund     if (e) return e;
2845e9cd1aeSAssar Westerlund     p += l;
2855e9cd1aeSAssar Westerlund     len -= l;
2865e9cd1aeSAssar Westerlund     ret += l;
2875e9cd1aeSAssar Westerlund     if(size) *size = ret;
2885e9cd1aeSAssar Westerlund     return 0;
2895e9cd1aeSAssar Westerlund }
2905e9cd1aeSAssar Westerlund 
2915e9cd1aeSAssar Westerlund int
2924137ff4cSJacques Vidrine decode_enumerated (const unsigned char *p, size_t len,
2934137ff4cSJacques Vidrine 		   unsigned *num, size_t *size)
2944137ff4cSJacques Vidrine {
2954137ff4cSJacques Vidrine     size_t ret = 0;
2964137ff4cSJacques Vidrine     size_t l, reallen;
2974137ff4cSJacques Vidrine     int e;
2984137ff4cSJacques Vidrine 
2994137ff4cSJacques Vidrine     e = der_match_tag (p, len, UNIV, PRIM, UT_Enumerated, &l);
3004137ff4cSJacques Vidrine     if (e) return e;
3014137ff4cSJacques Vidrine     p += l;
3024137ff4cSJacques Vidrine     len -= l;
3034137ff4cSJacques Vidrine     ret += l;
3044137ff4cSJacques Vidrine     e = der_get_length (p, len, &reallen, &l);
3054137ff4cSJacques Vidrine     if (e) return e;
3064137ff4cSJacques Vidrine     p += l;
3074137ff4cSJacques Vidrine     len -= l;
3084137ff4cSJacques Vidrine     ret += l;
3094137ff4cSJacques Vidrine     e = der_get_int (p, reallen, num, &l);
3104137ff4cSJacques Vidrine     if (e) return e;
3114137ff4cSJacques Vidrine     p += l;
3124137ff4cSJacques Vidrine     len -= l;
3134137ff4cSJacques Vidrine     ret += l;
3144137ff4cSJacques Vidrine     if(size) *size = ret;
3154137ff4cSJacques Vidrine     return 0;
3164137ff4cSJacques Vidrine }
3174137ff4cSJacques Vidrine 
3184137ff4cSJacques Vidrine int
319b528cefcSMark Murray decode_general_string (const unsigned char *p, size_t len,
320b528cefcSMark Murray 		       general_string *str, size_t *size)
321b528cefcSMark Murray {
322b528cefcSMark Murray     size_t ret = 0;
323b528cefcSMark Murray     size_t l;
324b528cefcSMark Murray     int e;
325b528cefcSMark Murray     size_t slen;
326b528cefcSMark Murray 
327b528cefcSMark Murray     e = der_match_tag (p, len, UNIV, PRIM, UT_GeneralString, &l);
328b528cefcSMark Murray     if (e) return e;
329b528cefcSMark Murray     p += l;
330b528cefcSMark Murray     len -= l;
331b528cefcSMark Murray     ret += l;
332b528cefcSMark Murray 
333b528cefcSMark Murray     e = der_get_length (p, len, &slen, &l);
334b528cefcSMark Murray     if (e) return e;
335b528cefcSMark Murray     p += l;
336b528cefcSMark Murray     len -= l;
337b528cefcSMark Murray     ret += l;
338b528cefcSMark Murray     if (len < slen)
339b528cefcSMark Murray 	return ASN1_OVERRUN;
340b528cefcSMark Murray 
341b528cefcSMark Murray     e = der_get_general_string (p, slen, str, &l);
342b528cefcSMark Murray     if (e) return e;
343b528cefcSMark Murray     p += l;
344b528cefcSMark Murray     len -= l;
345b528cefcSMark Murray     ret += l;
346b528cefcSMark Murray     if(size) *size = ret;
347b528cefcSMark Murray     return 0;
348b528cefcSMark Murray }
349b528cefcSMark Murray 
350b528cefcSMark Murray int
351b528cefcSMark Murray decode_octet_string (const unsigned char *p, size_t len,
352b528cefcSMark Murray 		     octet_string *k, size_t *size)
353b528cefcSMark Murray {
354b528cefcSMark Murray     size_t ret = 0;
355b528cefcSMark Murray     size_t l;
356b528cefcSMark Murray     int e;
357b528cefcSMark Murray     size_t slen;
358b528cefcSMark Murray 
359b528cefcSMark Murray     e = der_match_tag (p, len, UNIV, PRIM, UT_OctetString, &l);
360b528cefcSMark Murray     if (e) return e;
361b528cefcSMark Murray     p += l;
362b528cefcSMark Murray     len -= l;
363b528cefcSMark Murray     ret += l;
364b528cefcSMark Murray 
365b528cefcSMark Murray     e = der_get_length (p, len, &slen, &l);
366b528cefcSMark Murray     if (e) return e;
367b528cefcSMark Murray     p += l;
368b528cefcSMark Murray     len -= l;
369b528cefcSMark Murray     ret += l;
370b528cefcSMark Murray     if (len < slen)
371b528cefcSMark Murray 	return ASN1_OVERRUN;
372b528cefcSMark Murray 
373b528cefcSMark Murray     e = der_get_octet_string (p, slen, k, &l);
374b528cefcSMark Murray     if (e) return e;
375b528cefcSMark Murray     p += l;
376b528cefcSMark Murray     len -= l;
377b528cefcSMark Murray     ret += l;
378b528cefcSMark Murray     if(size) *size = ret;
379b528cefcSMark Murray     return 0;
380b528cefcSMark Murray }
381b528cefcSMark Murray 
3824137ff4cSJacques Vidrine int
3834137ff4cSJacques Vidrine decode_oid (const unsigned char *p, size_t len,
3844137ff4cSJacques Vidrine 	    oid *k, size_t *size)
3854137ff4cSJacques Vidrine {
3864137ff4cSJacques Vidrine     size_t ret = 0;
3874137ff4cSJacques Vidrine     size_t l;
3884137ff4cSJacques Vidrine     int e;
3894137ff4cSJacques Vidrine     size_t slen;
3904137ff4cSJacques Vidrine 
3914137ff4cSJacques Vidrine     e = der_match_tag (p, len, UNIV, PRIM, UT_OID, &l);
3924137ff4cSJacques Vidrine     if (e) return e;
3934137ff4cSJacques Vidrine     p += l;
3944137ff4cSJacques Vidrine     len -= l;
3954137ff4cSJacques Vidrine     ret += l;
3964137ff4cSJacques Vidrine 
3974137ff4cSJacques Vidrine     e = der_get_length (p, len, &slen, &l);
3984137ff4cSJacques Vidrine     if (e) return e;
3994137ff4cSJacques Vidrine     p += l;
4004137ff4cSJacques Vidrine     len -= l;
4014137ff4cSJacques Vidrine     ret += l;
4024137ff4cSJacques Vidrine     if (len < slen)
4034137ff4cSJacques Vidrine 	return ASN1_OVERRUN;
4044137ff4cSJacques Vidrine 
4054137ff4cSJacques Vidrine     e = der_get_oid (p, slen, k, &l);
4064137ff4cSJacques Vidrine     if (e) return e;
4074137ff4cSJacques Vidrine     p += l;
4084137ff4cSJacques Vidrine     len -= l;
4094137ff4cSJacques Vidrine     ret += l;
4104137ff4cSJacques Vidrine     if(size) *size = ret;
4114137ff4cSJacques Vidrine     return 0;
4124137ff4cSJacques Vidrine }
4134137ff4cSJacques Vidrine 
414b528cefcSMark Murray static void
415b528cefcSMark Murray generalizedtime2time (const char *s, time_t *t)
416b528cefcSMark Murray {
417b528cefcSMark Murray     struct tm tm;
418b528cefcSMark Murray 
419b528cefcSMark Murray     memset(&tm, 0, sizeof(tm));
420b528cefcSMark Murray     sscanf (s, "%04d%02d%02d%02d%02d%02dZ",
421b528cefcSMark Murray 	    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
422b528cefcSMark Murray 	    &tm.tm_min, &tm.tm_sec);
423b528cefcSMark Murray     tm.tm_year -= 1900;
424b528cefcSMark Murray     tm.tm_mon -= 1;
425b528cefcSMark Murray     *t = timegm (&tm);
426b528cefcSMark Murray }
427b528cefcSMark Murray 
428b528cefcSMark Murray int
429b528cefcSMark Murray decode_generalized_time (const unsigned char *p, size_t len,
430b528cefcSMark Murray 			 time_t *t, size_t *size)
431b528cefcSMark Murray {
432b528cefcSMark Murray     octet_string k;
433b528cefcSMark Murray     char *times;
434b528cefcSMark Murray     size_t ret = 0;
435b528cefcSMark Murray     size_t l;
436b528cefcSMark Murray     int e;
437b528cefcSMark Murray     size_t slen;
438b528cefcSMark Murray 
439b528cefcSMark Murray     e = der_match_tag (p, len, UNIV, PRIM, UT_GeneralizedTime, &l);
440b528cefcSMark Murray     if (e) return e;
441b528cefcSMark Murray     p += l;
442b528cefcSMark Murray     len -= l;
443b528cefcSMark Murray     ret += l;
444b528cefcSMark Murray 
445b528cefcSMark Murray     e = der_get_length (p, len, &slen, &l);
446b528cefcSMark Murray     if (e) return e;
447b528cefcSMark Murray     p += l;
448b528cefcSMark Murray     len -= l;
449b528cefcSMark Murray     ret += l;
450b528cefcSMark Murray     if (len < slen)
451b528cefcSMark Murray 	return ASN1_OVERRUN;
452b528cefcSMark Murray     e = der_get_octet_string (p, slen, &k, &l);
453b528cefcSMark Murray     if (e) return e;
454b528cefcSMark Murray     p += l;
455b528cefcSMark Murray     len -= l;
456b528cefcSMark Murray     ret += l;
457b528cefcSMark Murray     times = realloc(k.data, k.length + 1);
458b528cefcSMark Murray     if (times == NULL){
459b528cefcSMark Murray 	free(k.data);
460b528cefcSMark Murray 	return ENOMEM;
461b528cefcSMark Murray     }
462b528cefcSMark Murray     times[k.length] = 0;
463b528cefcSMark Murray     generalizedtime2time (times, t);
464b528cefcSMark Murray     free (times);
465b528cefcSMark Murray     if(size) *size = ret;
466b528cefcSMark Murray     return 0;
467b528cefcSMark Murray }
468b528cefcSMark Murray 
469b528cefcSMark Murray 
470b528cefcSMark Murray int
471b528cefcSMark Murray fix_dce(size_t reallen, size_t *len)
472b528cefcSMark Murray {
473b528cefcSMark Murray     if(reallen == ASN1_INDEFINITE)
474b528cefcSMark Murray 	return 1;
475b528cefcSMark Murray     if(*len < reallen)
476b528cefcSMark Murray 	return -1;
477b528cefcSMark Murray     *len = reallen;
478b528cefcSMark Murray     return 0;
479b528cefcSMark Murray }
480