1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * src/lib/krb5/asn.1/asn1_decode.c
5  *
6  * Copyright 1994, 2003 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
9  * Export of this software from the United States of America may
10  *   require a specific license from the United States Government.
11  *   It is the responsibility of any person or organization contemplating
12  *   export to obtain such a license before exporting.
13  *
14  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15  * distribute this software and its documentation for any purpose and
16  * without fee is hereby granted, provided that the above copyright
17  * notice appear in all copies and that both that copyright notice and
18  * this permission notice appear in supporting documentation, and that
19  * the name of M.I.T. not be used in advertising or publicity pertaining
20  * to distribution of the software without specific, written prior
21  * permission.  Furthermore if you modify this software you must label
22  * your software as modified software and not distribute it in such a
23  * fashion that it might be confused with the original M.I.T. software.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  */
28 
29 /* ASN.1 primitive decoders */
30 #include "asn1_decode.h"
31 #include "asn1_get.h"
32 #include <stdio.h>
33 #ifdef HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #ifdef TIME_WITH_SYS_TIME
36 #include <time.h>
37 #endif
38 #else
39 #include <time.h>
40 #endif
41 
42 #define setup()\
43 asn1_error_code retval;\
44 taginfo tinfo
45 
46 #define asn1class	(tinfo.asn1class)
47 #define construction	(tinfo.construction)
48 #define tagnum		(tinfo.tagnum)
49 #define length		(tinfo.length)
50 
51 #define tag(type)\
52 retval = asn1_get_tag_2(buf,&tinfo);\
53 if(retval) return retval;\
54 if(asn1class != UNIVERSAL || construction != PRIMITIVE || tagnum != type)\
55   return ASN1_BAD_ID
56 
57 #define cleanup()\
58 return 0
59 
60 time_t gmt_mktime (struct tm *);
61 
62 asn1_error_code asn1_decode_integer(asn1buf *buf, long int *val)
63 {
64   setup();
65   asn1_octet o;
66   long n = 0; /* initialize to keep gcc happy */
67   int i;
68 
69   tag(ASN1_INTEGER);
70 
71   for (i = 0; i < length; i++) {
72     retval = asn1buf_remove_octet(buf, &o);
73     if (retval) return retval;
74     if (!i) {
75       n = (0x80 & o) ? -1 : 0;	/* grab sign bit */
76       if (n < 0 && length > sizeof (long))
77 	return ASN1_OVERFLOW;
78       else if (length > sizeof (long) + 1) /* allow extra octet for positive */
79 	return ASN1_OVERFLOW;
80     }
81     n = (n << 8) | o;
82   }
83   *val = n;
84   cleanup();
85 }
86 
87 asn1_error_code asn1_decode_unsigned_integer(asn1buf *buf, long unsigned int *val)
88 {
89   setup();
90   asn1_octet o;
91   unsigned long n;
92   int i;
93 
94   tag(ASN1_INTEGER);
95 
96   for (i = 0, n = 0; i < length; i++) {
97     retval = asn1buf_remove_octet(buf, &o);
98     if(retval) return retval;
99     if (!i) {
100       if (0x80 & o)
101 	return ASN1_OVERFLOW;
102       else if (length > sizeof (long) + 1)
103 	return ASN1_OVERFLOW;
104     }
105     n = (n << 8) | o;
106   }
107   *val = n;
108   cleanup();
109 }
110 
111 /*
112  * asn1_decode_maybe_unsigned
113  *
114  * This is needed because older releases of MIT krb5 have signed
115  * sequence numbers.  We want to accept both signed and unsigned
116  * sequence numbers, in the range -2^31..2^32-1, mapping negative
117  * numbers into their positive equivalents in the same way that C's
118  * normal integer conversions do, i.e., would preserve bits on a
119  * two's-complement architecture.
120  */
121 asn1_error_code asn1_decode_maybe_unsigned(asn1buf *buf, unsigned long *val)
122 {
123   setup();
124   asn1_octet o;
125   unsigned long n, bitsremain;
126   unsigned int i;
127 
128   tag(ASN1_INTEGER);
129   o = 0;
130   n = 0;
131   bitsremain = ~0UL;
132   for (i = 0; i < length; i++) {
133     /* Accounts for u_long width not being a multiple of 8. */
134     if (bitsremain < 0xff) return ASN1_OVERFLOW;
135     retval = asn1buf_remove_octet(buf, &o);
136     if (retval) return retval;
137     if (bitsremain == ~0UL) {
138       if (i == 0)
139 	n = (o & 0x80) ? ~0UL : 0UL; /* grab sign bit */
140       /*
141        * Skip leading zero or 0xFF octets to humor non-compliant encoders.
142        */
143       if (n == 0 && o == 0)
144 	continue;
145       if (n == ~0UL && o == 0xff)
146 	continue;
147     }
148     n = (n << 8) | o;
149     bitsremain >>= 8;
150   }
151   *val = n;
152   cleanup();
153 }
154 
155 asn1_error_code asn1_decode_oid(asn1buf *buf, unsigned int *retlen, asn1_octet **val)
156 {
157   setup();
158   tag(ASN1_OBJECTIDENTIFIER);
159   retval = asn1buf_remove_octetstring(buf, length, val);
160   if (retval) return retval;
161   *retlen = length;
162   cleanup();
163 }
164 
165 asn1_error_code asn1_decode_octetstring(asn1buf *buf, unsigned int *retlen, asn1_octet **val)
166 {
167   setup();
168   tag(ASN1_OCTETSTRING);
169   retval = asn1buf_remove_octetstring(buf,length,val);
170   if(retval) return retval;
171   *retlen = length;
172   cleanup();
173 }
174 
175 asn1_error_code asn1_decode_charstring(asn1buf *buf, unsigned int *retlen, char **val)
176 {
177   setup();
178   tag(ASN1_OCTETSTRING);
179   retval = asn1buf_remove_charstring(buf,length,val);
180   if(retval) return retval;
181   *retlen = length;
182   cleanup();
183 }
184 
185 
186 asn1_error_code asn1_decode_generalstring(asn1buf *buf, unsigned int *retlen, char **val)
187 {
188   setup();
189   tag(ASN1_GENERALSTRING);
190   retval = asn1buf_remove_charstring(buf,length,val);
191   if(retval) return retval;
192   *retlen = length;
193   cleanup();
194 }
195 
196 
197 asn1_error_code asn1_decode_null(asn1buf *buf)
198 {
199   setup();
200   tag(ASN1_NULL);
201   if(length != 0) return ASN1_BAD_LENGTH;
202   cleanup();
203 }
204 
205 asn1_error_code asn1_decode_printablestring(asn1buf *buf, int *retlen, char **val)
206 {
207   setup();
208   tag(ASN1_PRINTABLESTRING);
209   retval = asn1buf_remove_charstring(buf,length,val);
210   if(retval) return retval;
211   *retlen = length;
212   cleanup();
213 }
214 
215 asn1_error_code asn1_decode_ia5string(asn1buf *buf, int *retlen, char **val)
216 {
217   setup();
218   tag(ASN1_IA5STRING);
219   retval = asn1buf_remove_charstring(buf,length,val);
220   if(retval) return retval;
221   *retlen = length;
222   cleanup();
223 }
224 
225 asn1_error_code asn1_decode_generaltime(asn1buf *buf, time_t *val)
226 {
227   setup();
228   char *s;
229   struct tm ts;
230   time_t t;
231 
232   tag(ASN1_GENERALTIME);
233 
234   if(length != 15) return ASN1_BAD_LENGTH;
235   retval = asn1buf_remove_charstring(buf,15,&s);
236   /* Time encoding: YYYYMMDDhhmmssZ */
237   if(s[14] != 'Z') {
238       free(s);
239       return ASN1_BAD_FORMAT;
240   }
241   if(s[0] == '1' && !memcmp("19700101000000Z", s, 15)) {
242       t = 0;
243       free(s);
244       goto done;
245   }
246 #define c2i(c) ((c)-'0')
247   ts.tm_year = 1000*c2i(s[0]) + 100*c2i(s[1]) + 10*c2i(s[2]) + c2i(s[3])
248     - 1900;
249   ts.tm_mon = 10*c2i(s[4]) + c2i(s[5]) - 1;
250   ts.tm_mday = 10*c2i(s[6]) + c2i(s[7]);
251   ts.tm_hour = 10*c2i(s[8]) + c2i(s[9]);
252   ts.tm_min = 10*c2i(s[10]) + c2i(s[11]);
253   ts.tm_sec = 10*c2i(s[12]) + c2i(s[13]);
254   ts.tm_isdst = -1;
255   t = gmt_mktime(&ts);
256   free(s);
257 
258   if(t == -1) return ASN1_BAD_TIMEFORMAT;
259 
260 done:
261   *val = t;
262   cleanup();
263 }
264