Imported Upstream version 1.15.2
[platform/upstream/krb5.git] / src / lib / krb5 / asn.1 / asn1buf.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* Coding Buffer Implementation */
3
4 /*
5  *  Implementation
6  *
7  *    Encoding mode
8  *
9  *    The encoding buffer is filled from bottom (lowest address) to top
10  *    (highest address).  This makes it easier to expand the buffer,
11  *    since realloc preserves the existing portion of the buffer.
12  *
13  *    Note: Since ASN.1 encoding must be done in reverse, this means
14  *    that you can't simply memcpy out the buffer data, since it will be
15  *    backwards.  You need to reverse-iterate through it, instead.
16  *
17  *    ***This decision may have been a mistake.  In practice, the
18  *    implementation will probably be tuned such that reallocation is
19  *    rarely necessary.  Also, the realloc probably has recopy the
20  *    buffer itself, so we don't really gain that much by avoiding an
21  *    explicit copy of the buffer.  --Keep this in mind for future reference.
22  *
23  *
24  *    Decoding mode
25  *
26  *    The decoding buffer is in normal order and is created by wrapping
27  *    an asn1buf around a krb5_data structure.
28  */
29
30 /*
31  * Abstraction Function
32  *
33  *   Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
34  *   These pointers must always point to a valid, allocated asn1buf
35  *   structure or be NULL.
36  *
37  *   The contents of the asn1buf represent an octet string.  This string
38  *   begins at base and continues to the octet immediately preceding next.
39  *   If next == base or mybuf == NULL, then the asn1buf represents an empty
40  *   octet string.
41  */
42
43 /*
44  * Representation Invariant
45  *
46  *   Pointers to asn1buf's must always point to a valid, allocated
47  *   asn1buf structure or be NULL.
48  *
49  *   base points to a valid, allocated octet array or is NULL
50  *   bound, if non-NULL, points to the last valid octet
51  *   next >= base
52  *   next <= bound+2  (i.e. next should be able to step just past the bound,
53  *                     but no further.  (The bound should move out in response
54  *                     to being crossed by next.))
55  */
56
57 #define ASN1BUF_OMIT_INLINE_FUNCS
58 #include "asn1buf.h"
59 #include <stdio.h>
60
61 #ifdef USE_VALGRIND
62 #include <valgrind/memcheck.h>
63 #else
64 #define VALGRIND_CHECK_READABLE(PTR,SIZE) ((void)0)
65 #endif
66
67 #if !defined(__GNUC__) || defined(CONFIG_SMALL)
68 /*
69  * Declare private procedures as static if they're not used for inline
70  * expansion of other stuff elsewhere.
71  */
72 static unsigned int asn1buf_free(const asn1buf *);
73 static asn1_error_code asn1buf_ensure_space(asn1buf *, unsigned int);
74 static asn1_error_code asn1buf_expand(asn1buf *, unsigned int);
75 #endif
76
77 #define asn1_is_eoc(class, num, indef)                  \
78     ((class) == UNIVERSAL && !(num) && !(indef))
79
80 asn1_error_code
81 asn1buf_create(asn1buf **buf)
82 {
83     *buf = (asn1buf*)malloc(sizeof(asn1buf));
84     if (*buf == NULL) return ENOMEM;
85     (*buf)->base = NULL;
86     (*buf)->bound = NULL;
87     (*buf)->next = NULL;
88     return 0;
89 }
90
91 void
92 asn1buf_destroy(asn1buf **buf)
93 {
94     if (*buf != NULL) {
95         free((*buf)->base);
96         free(*buf);
97         *buf = NULL;
98     }
99 }
100
101 #ifdef asn1buf_insert_octet
102 #undef asn1buf_insert_octet
103 #endif
104 asn1_error_code
105 asn1buf_insert_octet(asn1buf *buf, const int o)
106 {
107     asn1_error_code retval;
108
109     retval = asn1buf_ensure_space(buf,1U);
110     if (retval) return retval;
111     *(buf->next) = (char)o;
112     (buf->next)++;
113     return 0;
114 }
115
116 asn1_error_code
117 asn1buf_insert_bytestring(asn1buf *buf, const unsigned int len, const void *sv)
118 {
119     asn1_error_code retval;
120     unsigned int length;
121     const char *s = sv;
122
123     retval = asn1buf_ensure_space(buf,len);
124     if (retval) return retval;
125     VALGRIND_CHECK_READABLE(sv, len);
126     for (length=1; length<=len; length++,(buf->next)++)
127         *(buf->next) = (s[len-length]);
128     return 0;
129 }
130
131 asn1_error_code
132 asn12krb5_buf(const asn1buf *buf, krb5_data **code)
133 {
134     unsigned int i;
135     krb5_data *d;
136
137     *code = NULL;
138
139     d = calloc(1, sizeof(krb5_data));
140     if (d == NULL)
141         return ENOMEM;
142     d->length = asn1buf_len(buf);
143     d->data = malloc(d->length + 1);
144     if (d->data == NULL) {
145         free(d);
146         return ENOMEM;
147     }
148     for (i=0; i < d->length; i++)
149         d->data[i] = buf->base[d->length - i - 1];
150     d->data[d->length] = '\0';
151     d->magic = KV5M_DATA;
152     *code = d;
153     return 0;
154 }
155
156 /****************************************************************/
157 /* Private Procedures */
158
159 static int
160 asn1buf_size(const asn1buf *buf)
161 {
162     if (buf == NULL || buf->base == NULL) return 0;
163     return buf->bound - buf->base + 1;
164 }
165
166 #undef asn1buf_free
167 unsigned int
168 asn1buf_free(const asn1buf *buf)
169 {
170     if (buf == NULL || buf->base == NULL) return 0;
171     else return buf->bound - buf->next + 1;
172 }
173
174 #undef asn1buf_ensure_space
175 asn1_error_code
176 asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
177 {
178     unsigned int avail = asn1buf_free(buf);
179     if (avail >= amount)
180         return 0;
181     return asn1buf_expand(buf, amount-avail);
182 }
183
184 asn1_error_code
185 asn1buf_expand(asn1buf *buf, unsigned int inc)
186 {
187 #define STANDARD_INCREMENT 200
188     int next_offset = buf->next - buf->base;
189     int bound_offset;
190     if (buf->base == NULL) bound_offset = -1;
191     else bound_offset = buf->bound - buf->base;
192
193     if (inc < STANDARD_INCREMENT)
194         inc = STANDARD_INCREMENT;
195
196     buf->base = realloc(buf->base,
197                         (asn1buf_size(buf)+inc) * sizeof(asn1_octet));
198     if (buf->base == NULL) return ENOMEM; /* XXX leak */
199     buf->bound = (buf->base) + bound_offset + inc;
200     buf->next = (buf->base) + next_offset;
201     return 0;
202 }
203
204 #undef asn1buf_len
205 int
206 asn1buf_len(const asn1buf *buf)
207 {
208     return buf->next - buf->base;
209 }