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+2  (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     if (buf->bound - buf->next + 1 <= 0)
133       return ASN1_OVERRUN;
134     retval = asn1_get_tag_2(buf, &t);
135     if (retval) return retval;
136     if (!t.indef) {
137       if (t.length <= buf->bound - buf->next + 1)
138 	buf->next += t.length;
139       else
140 	return ASN1_OVERRUN;
141     }
142     if (t.indef)
143       nestlevel++;
144     if (asn1_is_eoc(t.asn1class, t.tagnum, t.indef))
145       nestlevel--;		/* got an EOC encoding */
146   }
147   return 0;
148 }
149 
150 asn1_error_code asn1buf_destroy(asn1buf **buf)
151 {
152   if (*buf != NULL) {
153     if ((*buf)->base != NULL) free((*buf)->base);
154     free(*buf);
155     *buf = NULL;
156   }
157   return 0;
158 }
159 
160 #ifdef asn1buf_insert_octet
161 #undef asn1buf_insert_octet
162 #endif
163 asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
164 {
165   asn1_error_code retval;
166 
167   retval = asn1buf_ensure_space(buf,1U);
168   if(retval) return retval;
169   *(buf->next) = (char)o;
170   (buf->next)++;
171   return 0;
172 }
173 
174 asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s)
175 {
176   asn1_error_code retval;
177   int length;
178 
179   retval = asn1buf_ensure_space(buf,len);
180   if(retval) return retval;
181   for(length=1; length<=len; length++,(buf->next)++)
182     *(buf->next) = (char)(s[len-length]);
183   return 0;
184 }
185 
186 asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s)
187 {
188   asn1_error_code retval;
189   int length;
190 
191   retval = asn1buf_ensure_space(buf,len);
192   if(retval) return retval;
193   for(length=1; length<=len; length++,(buf->next)++)
194     *(buf->next) = (char)(s[len-length]);
195   return 0;
196 }
197 
198 #undef asn1buf_remove_octet
199 asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o)
200 {
201   if(buf->next > buf->bound) return ASN1_OVERRUN;
202   *o = (asn1_octet)(*((buf->next)++));
203   return 0;
204 }
205 
206 asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, asn1_octet **s)
207 {
208   int i;
209 
210   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
211   if (len == 0) {
212       *s = 0;
213       return 0;
214   }
215   *s = (asn1_octet*)malloc(len*sizeof(asn1_octet));
216   if (*s == NULL)
217       return ENOMEM;
218   for(i=0; i<len; i++)
219     (*s)[i] = (asn1_octet)(buf->next)[i];
220   buf->next += len;
221   return 0;
222 }
223 
224 asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, char **s)
225 {
226   int i;
227 
228   if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
229   if (len == 0) {
230       *s = 0;
231       return 0;
232   }
233   *s = (char*)malloc(len*sizeof(char));
234   if (*s == NULL) return ENOMEM;
235   for(i=0; i<len; i++)
236     (*s)[i] = (char)(buf->next)[i];
237   buf->next += len;
238   return 0;
239 }
240 
241 int asn1buf_remains(asn1buf *buf, int indef)
242 {
243   int remain;
244   if(buf == NULL || buf->base == NULL) return 0;
245   remain = buf->bound - buf->next +1;
246   if (remain <= 0) return remain;
247   /*
248    * Two 0 octets means the end of an indefinite encoding.
249    */
250   if (indef && remain >= 2 && !*(buf->next) && !*(buf->next + 1))
251       return 0;
252   else return remain;
253 }
254 
255 asn1_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code)
256 {
257   int i;
258   *code = (krb5_data*)calloc(1,sizeof(krb5_data));
259   if(*code == NULL) return ENOMEM;
260   (*code)->magic = KV5M_DATA;
261   (*code)->data = NULL;
262   (*code)->length = 0;
263   (*code)->length = asn1buf_len(buf);
264   (*code)->data = (char*)malloc((((*code)->length)+1)*sizeof(char));
265   if ((*code)->data == NULL) {
266     free(*code);
267     *code = NULL;
268     return ENOMEM;
269   }
270   for(i=0; i < (*code)->length; i++)
271     ((*code)->data)[i] = (buf->base)[((*code)->length)-i-1];
272   ((*code)->data)[(*code)->length] = '\0';
273   return 0;
274 }
275 
276 
277 
278 /* These parse and unparse procedures should be moved out. They're
279    useful only for debugging and superfluous in the production version. */
280 
281 asn1_error_code asn1buf_unparse(const asn1buf *buf, char **s)
282 {
283   if(*s != NULL) free(*s);
284   if(buf == NULL){
285     *s = malloc(sizeof("<NULL>"));
286     if(*s == NULL) return ENOMEM;
287     strcpy(*s,"<NULL>");
288   }else if(buf->base == NULL){
289     *s = malloc(sizeof("<EMPTY>"));
290     if(*s == NULL) return ENOMEM;
291     strcpy(*s,"<EMPTY>");
292   }else{
293     unsigned int length = asn1buf_len(buf);
294     int i;
295 
296     *s = calloc(length+1, sizeof(char));
297     if(*s == NULL) return ENOMEM;
298     (*s)[length] = '\0';
299     for(i=0; i<length; i++) ;
300 /*      OLDDECLARG( (*s)[i] = , (buf->base)[length-i-1]) */
301   }
302   return 0;
303 }
304 
305 asn1_error_code asn1buf_hex_unparse(const asn1buf *buf, char **s)
306 {
307 #define hexchar(d) ((d)<=9 ? ('0'+(d)) :\
308 		    ((d)<=15 ? ('A'+(d)-10) :\
309 		    'X'))
310 
311   if(*s != NULL) free(*s);
312 
313   if(buf == NULL){
314     *s = malloc(sizeof("<NULL>"));
315     if(*s == NULL) return ENOMEM;
316     strcpy(*s,"<NULL>");
317   }else if(buf->base == NULL){
318     *s = malloc(sizeof("<EMPTY>"));
319     if(*s == NULL) return ENOMEM;
320     strcpy(*s,"<EMPTY>");
321   }else{
322     unsigned int length = asn1buf_len(buf);
323     int i;
324 
325     *s = malloc(3*length);
326     if(*s == NULL) return ENOMEM;
327     for(i = length-1; i >= 0; i--){
328       (*s)[3*(length-i-1)] = hexchar(((buf->base)[i]&0xF0)>>4);
329       (*s)[3*(length-i-1)+1] = hexchar((buf->base)[i]&0x0F);
330       (*s)[3*(length-i-1)+2] = ' ';
331     }
332     (*s)[3*length-1] = '\0';
333   }
334   return 0;
335 }
336 
337 /****************************************************************/
338 /* Private Procedures */
339 
340 #undef asn1buf_size
341 int asn1buf_size(const asn1buf *buf)
342 {
343   if(buf == NULL || buf->base == NULL) return 0;
344   return buf->bound - buf->base + 1;
345 }
346 
347 #undef asn1buf_free
348 int asn1buf_free(const asn1buf *buf)
349 {
350   if(buf == NULL || buf->base == NULL) return 0;
351   else return buf->bound - buf->next + 1;
352 }
353 
354 #undef asn1buf_ensure_space
355 asn1_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
356 {
357   int avail = asn1buf_free(buf);
358   if(avail < amount){
359     asn1_error_code retval = asn1buf_expand(buf, amount-avail);
360     if(retval) return retval;
361   }
362   return 0;
363 }
364 
365 asn1_error_code asn1buf_expand(asn1buf *buf, unsigned int inc)
366 {
367 #define STANDARD_INCREMENT 200
368   int next_offset = buf->next - buf->base;
369   int bound_offset;
370   if (buf->base == NULL) bound_offset = -1;
371   else bound_offset = buf->bound - buf->base;
372 
373   if (inc < STANDARD_INCREMENT)
374     inc = STANDARD_INCREMENT;
375 
376   if (buf->base == NULL)
377     buf->base = malloc((asn1buf_size(buf)+inc) * sizeof(asn1_octet));
378   else
379     buf->base = realloc(buf->base,
380 			(asn1buf_size(buf)+inc) * sizeof(asn1_octet));
381   if (buf->base == NULL) return ENOMEM;
382   buf->bound = (buf->base) + bound_offset + inc;
383   buf->next = (buf->base) + next_offset;
384   return 0;
385 }
386 
387 #undef asn1buf_len
388 int asn1buf_len(const asn1buf *buf)
389 {
390   return buf->next - buf->base;
391 }
392