1/*
2 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/* Coding Buffer Implementation */
7
8/*
9  Implementation
10
11    Encoding mode
12
13    The encoding buffer is filled from bottom (lowest address) to top
14    (highest address).  This makes it easier to expand the buffer,
15    since realloc preserves the existing portion of the buffer.
16
17    Note: Since ASN.1 encoding must be done in reverse, this means
18    that you can't simply memcpy out the buffer data, since it will be
19    backwards.  You need to reverse-iterate through it, instead.
20
21    ***This decision may have been a mistake.  In practice, the
22    implementation will probably be tuned such that reallocation is
23    rarely necessary.  Also, the realloc probably has recopy the
24    buffer itself, so we don't really gain that much by avoiding an
25    explicit copy of the buffer.  --Keep this in mind for future reference.
26
27
28    Decoding mode
29
30    The decoding buffer is in normal order and is created by wrapping
31    an asn1buf around a krb5_data structure.
32  */
33
34/* Abstraction Function
35
36   Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
37   These pointers must always point to a valid, allocated asn1buf
38   structure or be NULL.
39
40   The contents of the asn1buf represent an octet string.  This string
41   begins at base and continues to the octet immediately preceding next.
42   If next == base or mybuf == NULL, then the asn1buf represents an empty
43   octet string. */
44
45/* Representation Invariant
46
47   Pointers to asn1buf's must always point to a valid, allocated
48   asn1buf structure or be NULL.
49
50   base points to a valid, allocated octet array or is NULL
51   bound, if non-NULL, points to the last valid octet
52   next >= base
53   next <= bound+2  (i.e. next should be able to step just past the bound,
54                     but no further.  (The bound should move out in response
55		     to being crossed by next.)) */
56
57#define ASN1BUF_OMIT_INLINE_FUNCS
58#include "asn1buf.h"
59#undef ASN1BUF_OMIT_INLINE_FUNCS
60#include <stdio.h>
61#include "asn1_get.h"
62
63#define asn1_is_eoc(class, num, indef)	\
64((class) == UNIVERSAL && !(num) && !(indef))
65
66asn1_error_code asn1buf_create(asn1buf **buf)
67{
68  *buf = (asn1buf*)malloc(sizeof(asn1buf));
69  if (*buf == NULL) return ENOMEM;
70  (*buf)->base = NULL;
71  (*buf)->bound = NULL;
72  (*buf)->next = NULL;
73  return 0;
74}
75
76asn1_error_code asn1buf_wrap_data(asn1buf *buf, const krb5_data *code)
77{
78  if(code == NULL || code->data == NULL) return ASN1_MISSING_FIELD;
79  buf->next = buf->base = code->data;
80  buf->bound = code->data + code->length - 1;
81  return 0;
82}
83
84asn1_error_code asn1buf_imbed(asn1buf *subbuf, const asn1buf *buf, const unsigned int length, const int indef)
85{
86  if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
87  subbuf->base = subbuf->next = buf->next;
88  if (!indef) {
89      if (length > (size_t)(buf->bound + 1 - buf->next)) return ASN1_OVERRUN;
90      subbuf->bound = subbuf->base + length - 1;
91  } else /* constructed indefinite */
92      subbuf->bound = buf->bound;
93  return 0;
94}
95
96asn1_error_code asn1buf_sync(asn1buf *buf, asn1buf *subbuf,
97			     asn1_class asn1class, asn1_tagnum lasttag,
98			     unsigned int length, int indef, int seqindef)
99{
100  asn1_error_code retval;
101
102  if (!seqindef) {
103    /* sequence was encoded as definite length */
104    buf->next = subbuf->bound + 1;
105  } else if (!asn1_is_eoc(asn1class, lasttag, indef)) {
106      retval = asn1buf_skiptail(subbuf, length, indef);
107      if (retval)
108	  return retval;
109  } else {
110    /* We have just read the EOC octets. */
111    buf->next = subbuf->next;
112  }
113  return 0;
114}
115
116asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const int indef)
117{
118  asn1_error_code retval;
119  taginfo t;
120  int nestlevel;
121
122  nestlevel = 1 + indef;
123  if (!indef) {
124    if (length <= buf->bound - buf->next + 1)
125      buf->next += length;
126    else
127      return ASN1_OVERRUN;
128  }
129  while (nestlevel > 0) {
130    if (buf->bound - buf->next + 1 <= 0)
131      return ASN1_OVERRUN;
132    retval = asn1_get_tag_2(buf, &t);
133    if (retval) return retval;
134    if (!t.indef) {
135      if (t.length <= buf->bound - buf->next + 1)
136	buf->next += t.length;
137      else
138	return ASN1_OVERRUN;
139    }
140    if (t.indef)
141      nestlevel++;
142    if (asn1_is_eoc(t.asn1class, t.tagnum, t.indef))
143      nestlevel--;		/* got an EOC encoding */
144  }
145  return 0;
146}
147
148asn1_error_code asn1buf_destroy(asn1buf **buf)
149{
150  if (*buf != NULL) {
151    if ((*buf)->base != NULL) free((*buf)->base);
152    free(*buf);
153    *buf = NULL;
154  }
155  return 0;
156}
157
158#ifdef asn1buf_insert_octet
159#undef asn1buf_insert_octet
160#endif
161asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
162{
163  asn1_error_code retval;
164
165  retval = asn1buf_ensure_space(buf,1U);
166  if(retval) return retval;
167  *(buf->next) = (char)o;
168  (buf->next)++;
169  return 0;
170}
171
172asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s)
173{
174  asn1_error_code retval;
175  int length;
176
177  retval = asn1buf_ensure_space(buf,len);
178  if(retval) return retval;
179  for(length=1; length<=len; length++,(buf->next)++)
180    *(buf->next) = (char)(s[len-length]);
181  return 0;
182}
183
184asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s)
185{
186  asn1_error_code retval;
187  int length;
188
189  retval = asn1buf_ensure_space(buf,len);
190  if(retval) return retval;
191  for(length=1; length<=len; length++,(buf->next)++)
192    *(buf->next) = (char)(s[len-length]);
193  return 0;
194}
195
196#undef asn1buf_remove_octet
197asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o)
198{
199  if(buf->next > buf->bound) return ASN1_OVERRUN;
200  *o = (asn1_octet)(*((buf->next)++));
201  return 0;
202}
203
204asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, asn1_octet **s)
205{
206  int i;
207
208  if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
209  if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
210  if (len == 0) {
211      *s = 0;
212      return 0;
213  }
214  *s = (asn1_octet*)malloc(len*sizeof(asn1_octet));
215  if (*s == NULL)
216      return ENOMEM;
217  for(i=0; i<len; i++)
218    (*s)[i] = (asn1_octet)(buf->next)[i];
219  buf->next += len;
220  return 0;
221}
222
223asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, char **s)
224{
225  int i;
226
227  if (buf->next > buf->bound + 1) return ASN1_OVERRUN;
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
241int 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
255asn1_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
281asn1_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
305asn1_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
341int 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
348int 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
355asn1_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
365asn1_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
388int asn1buf_len(const asn1buf *buf)
389{
390  return buf->next - buf->base;
391}
392