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