1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /* Coding Buffer Implementation */
9 
10 /*
11   Implementation
12 
13     Encoding mode
14 
15     The encoding buffer is filled from bottom (lowest address) to top
16     (highest address).  This makes it easier to expand the buffer,
17     since realloc preserves the existing portion of the buffer.
18 
19     Note: Since ASN.1 encoding must be done in reverse, this means
20     that you can't simply memcpy out the buffer data, since it will be
21     backwards.  You need to reverse-iterate through it, instead.
22 
23     ***This decision may have been a mistake.  In practice, the
24     implementation will probably be tuned such that reallocation is
25     rarely necessary.  Also, the realloc probably has recopy the
26     buffer itself, so we don't really gain that much by avoiding an
27     explicit copy of the buffer.  --Keep this in mind for future reference.
28 
29 
30     Decoding mode
31 
32     The decoding buffer is in normal order and is created by wrapping
33     an asn1buf around a krb5_data structure.
34   */
35 
36 /* Abstraction Function
37 
38    Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
39    These pointers must always point to a valid, allocated asn1buf
40    structure or be NULL.
41 
42    The contents of the asn1buf represent an octet string.  This string
43    begins at base and continues to the octet immediately preceding next.
44    If next == base or mybuf == NULL, then the asn1buf represents an empty
45    octet string. */
46 
47 /* Representation Invariant
48 
49    Pointers to asn1buf's must always point to a valid, allocated
50    asn1buf structure or be NULL.
51 
52    base points to a valid, allocated octet array or is NULL
53    bound, if non-NULL, points to the last valid octet
54    next >= base
55    next <= bound+1  (i.e. next should be able to step just past the bound,
56                      but no further.  (The bound should move out in response
57 		     to being crossed by next.)) */
58 
59 #define ASN1BUF_OMIT_INLINE_FUNCS
60 #include "asn1buf.h"
61 #undef ASN1BUF_OMIT_INLINE_FUNCS
62 #include <stdio.h>
63 #include "asn1_get.h"
64 
65 #define asn1_is_eoc(class, num, indef)	\
66 ((class) == UNIVERSAL && !(num) && !(indef))
67 
68 asn1_error_code asn1buf_create(asn1buf **buf)
69 {
70   *buf = (asn1buf*)malloc(sizeof(asn1buf));
71   if (*buf == NULL) return ENOMEM;
72   (*buf)->base = NULL;
73   (*buf)->bound = NULL;
74   (*buf)->next = NULL;
75   return 0;
76 }
77 
78 asn1_error_code asn1buf_wrap_data(asn1buf *buf, const krb5_data *code)
79 {
80   if(code == NULL || code->data == NULL) return ASN1_MISSING_FIELD;
81   buf->next = buf->base = code->data;
82   buf->bound = code->data + code->length - 1;
83   return 0;
84 }
85 
86 asn1_error_code asn1buf_imbed(asn1buf *subbuf, const asn1buf *buf, const unsigned int length, const int indef)
87 {
88   subbuf->base = subbuf->next = buf->next;
89   if (!indef) {
90       subbuf->bound = subbuf->base + length - 1;
91       if (subbuf->bound > buf->bound)
92 	  return ASN1_OVERRUN;
93   } else /* constructed indefinite */
94       subbuf->bound = buf->bound;
95   return 0;
96 }
97 
98 asn1_error_code asn1buf_sync(asn1buf *buf, asn1buf *subbuf,
99 			     asn1_class asn1class, asn1_tagnum lasttag,
100 			     unsigned int length, int indef, int seqindef)
101 {
102   asn1_error_code retval;
103 
104   if (!seqindef) {
105     /* sequence was encoded as definite length */
106     buf->next = subbuf->bound + 1;
107   } else if (!asn1_is_eoc(asn1class, lasttag, indef)) {
108       retval = asn1buf_skiptail(subbuf, length, indef);
109       if (retval)
110 	  return retval;
111   } else {
112     /* We have just read the EOC octets. */
113     buf->next = subbuf->next;
114   }
115   return 0;
116 }
117 
118 asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const int indef)
119 {
120   asn1_error_code retval;
121   taginfo t;
122   int nestlevel;
123 
124   nestlevel = 1 + indef;
125   if (!indef) {
126     if (length <= buf->bound - buf->next + 1)
127       buf->next += length;
128     else
129       return ASN1_OVERRUN;
130   }
131   while (nestlevel > 0) {
132     retval = asn1_get_tag_2(buf, &t);
133     if (retval) return retval;
134 
135     /*
136      * asn1_get_tag_2() sets tagnum=ASN1_TAGNUM_CEILING if there is a problem
137      * with the buffer, including overrun.
138      */
139 
140     if (t.tagnum == ASN1_TAGNUM_CEILING)
141 	return ASN1_OVERRUN;
142 
143     if (!t.indef) {
144       if (t.length <= buf->bound - buf->next + 1)
145 	buf->next += t.length;
146       else
147 	return ASN1_OVERRUN;
148     }
149     if (t.indef)
150       nestlevel++;
151     if (asn1_is_eoc(t.asn1class, t.tagnum, t.indef))
152       nestlevel--;		/* got an EOC encoding */
153   }
154   return 0;
155 }
156 
157 asn1_error_code asn1buf_destroy(asn1buf **buf)
158 {
159   if (*buf != NULL) {
160     if ((*buf)->base != NULL) free((*buf)->base);
161     free(*buf);
162     *buf = NULL;
163   }
164   return 0;
165 }
166 
167 #ifdef asn1buf_insert_octet
168 #undef asn1buf_insert_octet
169 #endif
170 asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
171 {
172   asn1_error_code retval;
173 
174   retval = asn1buf_ensure_space(buf,1U);
175   if(retval) return retval;
176   *(buf->next) = (char)o;
177   (buf->next)++;
178   return 0;
179 }
180 
181 asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s)
182 {
183   asn1_error_code retval;
184   int length;
185 
186   retval = asn1buf_ensure_space(buf,len);
187   if(retval) return retval;
188   for(length=1; length<=len; length++,(buf->next)++)
189     *(buf->next) = (char)(s[len-length]);
190   return 0;
191 }
192 
193 asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s)
194 {
195   asn1_error_code retval;
196   int length;
197 
198   retval = asn1buf_ensure_space(buf,len);
199   if(retval) return retval;
200   for(length=1; length<=len; length++,(buf->next)++)
201     *(buf->next) = (char)(s[len-length]);
202   return 0;
203 }
204 
205 #undef asn1buf_remove_octet
206 asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o)
207 {
208   if(buf->next > buf->bound) return ASN1_OVERRUN;
209   *o = (asn1_octet)(*((buf->next)++));
210   return 0;
211 }
212 
213 asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, asn1_octet **s)
214 {
215   int i;
216 
217   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
218   if (len == 0) {
219       *s = 0;
220       return 0;
221   }
222   *s = (asn1_octet*)malloc(len*sizeof(asn1_octet));
223   if (*s == NULL)
224       return ENOMEM;
225   for(i=0; i<len; i++)
226     (*s)[i] = (asn1_octet)(buf->next)[i];
227   buf->next += len;
228   return 0;
229 }
230 
231 asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, char **s)
232 {
233   int i;
234 
235   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
236   if (len == 0) {
237       *s = 0;
238       return 0;
239   }
240   *s = (char*)malloc(len*sizeof(char));
241   if (*s == NULL) return ENOMEM;
242   for(i=0; i<len; i++)
243     (*s)[i] = (char)(buf->next)[i];
244   buf->next += len;
245   return 0;
246 }
247 
248 int asn1buf_remains(asn1buf *buf, int indef)
249 {
250   int remain;
251   if(buf == NULL || buf->base == NULL) return 0;
252   remain = buf->bound - buf->next +1;
253   if (remain <= 0) return remain;
254   /*
255    * Two 0 octets means the end of an indefinite encoding.
256    */
257   if (indef && remain >= 2 && !*(buf->next) && !*(buf->next + 1))
258       return 0;
259   else return remain;
260 }
261 
262 asn1_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code)
263 {
264   int i;
265   *code = (krb5_data*)calloc(1,sizeof(krb5_data));
266   if(*code == NULL) return ENOMEM;
267   (*code)->magic = KV5M_DATA;
268   (*code)->data = NULL;
269   (*code)->length = 0;
270   (*code)->length = asn1buf_len(buf);
271   (*code)->data = (char*)malloc((((*code)->length)+1)*sizeof(char));
272   if ((*code)->data == NULL) {
273     free(*code);
274     *code = NULL;
275     return ENOMEM;
276   }
277   for(i=0; i < (*code)->length; i++)
278     ((*code)->data)[i] = (buf->base)[((*code)->length)-i-1];
279   ((*code)->data)[(*code)->length] = '\0';
280   return 0;
281 }
282 
283 
284 
285 /* These parse and unparse procedures should be moved out. They're
286    useful only for debugging and superfluous in the production version. */
287 
288 asn1_error_code asn1buf_unparse(const asn1buf *buf, char **s)
289 {
290   if(*s != NULL) free(*s);
291   if(buf == NULL){
292     *s = malloc(sizeof("<NULL>"));
293     if(*s == NULL) return ENOMEM;
294     strcpy(*s,"<NULL>");
295   }else if(buf->base == NULL){
296     *s = malloc(sizeof("<EMPTY>"));
297     if(*s == NULL) return ENOMEM;
298     strcpy(*s,"<EMPTY>");
299   }else{
300     unsigned int length = asn1buf_len(buf);
301     int i;
302 
303     *s = calloc(length+1, sizeof(char));
304     if(*s == NULL) return ENOMEM;
305     (*s)[length] = '\0';
306     for(i=0; i<length; i++) ;
307 /*      OLDDECLARG( (*s)[i] = , (buf->base)[length-i-1]) */
308   }
309   return 0;
310 }
311 
312 asn1_error_code asn1buf_hex_unparse(const asn1buf *buf, char **s)
313 {
314 #define hexchar(d) ((d)<=9 ? ('0'+(d)) :\
315 		    ((d)<=15 ? ('A'+(d)-10) :\
316 		    'X'))
317 
318   if(*s != NULL) free(*s);
319 
320   if(buf == NULL){
321     *s = malloc(sizeof("<NULL>"));
322     if(*s == NULL) return ENOMEM;
323     strcpy(*s,"<NULL>");
324   }else if(buf->base == NULL){
325     *s = malloc(sizeof("<EMPTY>"));
326     if(*s == NULL) return ENOMEM;
327     strcpy(*s,"<EMPTY>");
328   }else{
329     unsigned int length = asn1buf_len(buf);
330     int i;
331 
332     *s = malloc(3*length);
333     if(*s == NULL) return ENOMEM;
334     for(i = length-1; i >= 0; i--){
335       (*s)[3*(length-i-1)] = hexchar(((buf->base)[i]&0xF0)>>4);
336       (*s)[3*(length-i-1)+1] = hexchar((buf->base)[i]&0x0F);
337       (*s)[3*(length-i-1)+2] = ' ';
338     }
339     (*s)[3*length-1] = '\0';
340   }
341   return 0;
342 }
343 
344 /****************************************************************/
345 /* Private Procedures */
346 
347 #undef asn1buf_size
348 int asn1buf_size(const asn1buf *buf)
349 {
350   if(buf == NULL || buf->base == NULL) return 0;
351   return buf->bound - buf->base + 1;
352 }
353 
354 #undef asn1buf_free
355 int asn1buf_free(const asn1buf *buf)
356 {
357   if(buf == NULL || buf->base == NULL) return 0;
358   else return buf->bound - buf->next + 1;
359 }
360 
361 #undef asn1buf_ensure_space
362 asn1_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
363 {
364   int avail = asn1buf_free(buf);
365   if(avail < amount){
366     asn1_error_code retval = asn1buf_expand(buf, amount-avail);
367     if(retval) return retval;
368   }
369   return 0;
370 }
371 
372 asn1_error_code asn1buf_expand(asn1buf *buf, unsigned int inc)
373 {
374 #define STANDARD_INCREMENT 200
375   int next_offset = buf->next - buf->base;
376   int bound_offset;
377   if (buf->base == NULL) bound_offset = -1;
378   else bound_offset = buf->bound - buf->base;
379 
380   if (inc < STANDARD_INCREMENT)
381     inc = STANDARD_INCREMENT;
382 
383   if (buf->base == NULL)
384     buf->base = malloc((asn1buf_size(buf)+inc) * sizeof(asn1_octet));
385   else
386     buf->base = realloc(buf->base,
387 			(asn1buf_size(buf)+inc) * sizeof(asn1_octet));
388   if (buf->base == NULL) return ENOMEM;
389   buf->bound = (buf->base) + bound_offset + inc;
390   buf->next = (buf->base) + next_offset;
391   return 0;
392 }
393 
394 #undef asn1buf_len
395 int asn1buf_len(const asn1buf *buf)
396 {
397   return buf->next - buf->base;
398 }
399