1175a7fe650f6619f2183ac18981dad80dbe48b4
[samba.git] / source3 / libsmb / asn1.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    simple SPNEGO routines
5    Copyright (C) Andrew Tridgell 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /* free an asn1 structure */
25 void asn1_free(ASN1_DATA *data)
26 {
27         SAFE_FREE(data->data);
28 }
29
30 /* write to the ASN1 buffer, advancing the buffer pointer */
31 BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
32 {
33         if (data->has_error) return False;
34         if (data->length < data->ofs+len) {
35                 uint8 *newp;
36                 newp = Realloc(data->data, data->ofs+len);
37                 if (!newp) {
38                         SAFE_FREE(data->data);
39                         data->has_error = True;
40                         return False;
41                 }
42                 data->data = newp;
43                 data->length = data->ofs+len;
44         }
45         memcpy(data->data + data->ofs, p, len);
46         data->ofs += len;
47         return True;
48 }
49
50 /* useful fn for writing a uint8 */
51 BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
52 {
53         return asn1_write(data, &v, 1);
54 }
55
56 /* push a tag onto the asn1 data buffer. Used for nested structures */
57 BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
58 {
59         struct nesting *nesting;
60
61         asn1_write_uint8(data, tag);
62         nesting = (struct nesting *)malloc(sizeof(struct nesting));
63         if (!nesting) {
64                 data->has_error = True;
65                 return False;
66         }
67
68         nesting->start = data->ofs;
69         nesting->next = data->nesting;
70         data->nesting = nesting;
71         return asn1_write_uint8(data, 0xff);
72 }
73
74 /* pop a tag */
75 BOOL asn1_pop_tag(ASN1_DATA *data)
76 {
77         struct nesting *nesting;
78         size_t len;
79
80         nesting = data->nesting;
81
82         if (!nesting) {
83                 data->has_error = True;
84                 return False;
85         }
86         len = data->ofs - (nesting->start+1);
87         /* yes, this is ugly. We don't know in advance how many bytes the length
88            of a tag will take, so we assumed 1 byte. If we were wrong then we 
89            need to correct our mistake */
90         if (len > 255) {
91                 data->data[nesting->start] = 0x82;
92                 if (!asn1_write_uint8(data, 0)) return False;
93                 if (!asn1_write_uint8(data, 0)) return False;
94                 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
95                 data->data[nesting->start+1] = len>>8;
96                 data->data[nesting->start+2] = len&0xff;
97         } else if (len > 127) {
98                 data->data[nesting->start] = 0x81;
99                 if (!asn1_write_uint8(data, 0)) return False;
100                 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
101                 data->data[nesting->start+1] = len;
102         } else {
103                 data->data[nesting->start] = len;
104         }
105
106         data->nesting = nesting->next;
107         free(nesting);
108         return True;
109 }
110
111
112 /* write an integer */
113 BOOL asn1_write_Integer(ASN1_DATA *data, int i)
114 {
115         if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
116         do {
117                 asn1_write_uint8(data, i);
118                 i = i >> 8;
119         } while (i);
120         return asn1_pop_tag(data);
121 }
122
123 /* write an object ID to a ASN1 buffer */
124 BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
125 {
126         unsigned v, v2;
127         const char *p = (const char *)OID;
128         char *newp;
129
130         if (!asn1_push_tag(data, ASN1_OID))
131                 return False;
132         v = strtol(p, &newp, 10);
133         p = newp;
134         v2 = strtol(p, &newp, 10);
135         p = newp;
136         if (!asn1_write_uint8(data, 40*v + v2))
137                 return False;
138
139         while (*p) {
140                 v = strtol(p, &newp, 10);
141                 p = newp;
142                 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
143                 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
144                 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
145                 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
146                 if (!asn1_write_uint8(data, v&0x7f))
147                         return False;
148         }
149         return asn1_pop_tag(data);
150 }
151
152 /* write an octet string */
153 BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
154 {
155         asn1_push_tag(data, ASN1_OCTET_STRING);
156         asn1_write(data, p, length);
157         asn1_pop_tag(data);
158         return !data->has_error;
159 }
160
161 /* write a general string */
162 BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
163 {
164         asn1_push_tag(data, ASN1_GENERAL_STRING);
165         asn1_write(data, s, strlen(s));
166         asn1_pop_tag(data);
167         return !data->has_error;
168 }
169
170 /* write a BOOLEAN */
171 BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
172 {
173         asn1_write_uint8(data, ASN1_BOOLEAN);
174         asn1_write_uint8(data, v);
175         return !data->has_error;
176 }
177
178 /* check a BOOLEAN */
179 BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
180 {
181         uint8 b = 0;
182
183         asn1_read_uint8(data, &b);
184         if (b != ASN1_BOOLEAN) {
185                 data->has_error = True;
186                 return False;
187         }
188         asn1_read_uint8(data, &b);
189         if (b != v) {
190                 data->has_error = True;
191                 return False;
192         }
193         return !data->has_error;
194 }
195
196
197 /* load a ASN1_DATA structure with a lump of data, ready to be parsed */
198 BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
199 {
200         ZERO_STRUCTP(data);
201         data->data = memdup(blob.data, blob.length);
202         if (!data->data) {
203                 data->has_error = True;
204                 return False;
205         }
206         data->length = blob.length;
207         return True;
208 }
209
210 /* read from a ASN1 buffer, advancing the buffer pointer */
211 BOOL asn1_read(ASN1_DATA *data, void *p, int len)
212 {
213         if (data->ofs + len > data->length) {
214                 data->has_error = True;
215                 return False;
216         }
217         memcpy(p, data->data + data->ofs, len);
218         data->ofs += len;
219         return True;
220 }
221
222 /* read a uint8 from a ASN1 buffer */
223 BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
224 {
225         return asn1_read(data, v, 1);
226 }
227
228 /* start reading a nested asn1 structure */
229 BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
230 {
231         uint8 b;
232         struct nesting *nesting;
233         
234         asn1_read_uint8(data, &b);
235         if (b != tag) {
236                 data->has_error = True;
237                 return False;
238         }
239         nesting = (struct nesting *)malloc(sizeof(struct nesting));
240         if (!nesting) {
241                 data->has_error = True;
242                 return False;
243         }
244
245         asn1_read_uint8(data, &b);
246         if (b & 0x80) {
247                 int n = b & 0x7f;
248                 if (n > 2) {
249                         data->has_error = True;
250                         return False;
251                 }
252                 asn1_read_uint8(data, &b);
253                 nesting->taglen = b;
254                 if (n == 2) {
255                         asn1_read_uint8(data, &b);
256                         nesting->taglen = (nesting->taglen << 8) | b;
257                 }
258         } else {
259                 nesting->taglen = b;
260         }
261         nesting->start = data->ofs;
262         nesting->next = data->nesting;
263         data->nesting = nesting;
264         return !data->has_error;
265 }
266
267
268 /* stop reading a tag */
269 BOOL asn1_end_tag(ASN1_DATA *data)
270 {
271         struct nesting *nesting;
272
273         /* make sure we read it all */
274         if (asn1_tag_remaining(data) != 0) {
275                 data->has_error = True;
276                 return False;
277         }
278
279         nesting = data->nesting;
280
281         if (!nesting) {
282                 data->has_error = True;
283                 return False;
284         }
285
286         data->nesting = nesting->next;
287         free(nesting);
288         return True;
289 }
290
291 /* work out how many bytes are left in this nested tag */
292 int asn1_tag_remaining(ASN1_DATA *data)
293 {
294         if (!data->nesting) {
295                 data->has_error = True;
296                 return -1;
297         }
298         return data->nesting->taglen - (data->ofs - data->nesting->start);
299 }
300
301 /* read an object ID from a ASN1 buffer */
302 BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
303 {
304         uint8 b;
305         pstring oid;
306         fstring el;
307
308         if (!asn1_start_tag(data, ASN1_OID)) return False;
309         asn1_read_uint8(data, &b);
310
311         oid[0] = 0;
312         snprintf(el, sizeof(el), "%u",  b/40);
313         pstrcat(oid, el);
314         snprintf(el, sizeof(el), " %u",  b%40);
315         pstrcat(oid, el);
316
317         while (asn1_tag_remaining(data) > 0) {
318                 unsigned v = 0;
319                 do {
320                         asn1_read_uint8(data, &b);
321                         v = (v<<7) | (b&0x7f);
322                 } while (!data->has_error && b & 0x80);
323                 snprintf(el, sizeof(el), " %u",  v);
324                 pstrcat(oid, el);
325         }
326
327         asn1_end_tag(data);
328
329         *OID = strdup(oid);
330
331         return !data->has_error;
332 }
333
334 /* check that the next object ID is correct */
335 BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
336 {
337         char *id;
338
339         if (!asn1_read_OID(data, &id)) return False;
340
341         if (strcmp(id, OID) != 0) {
342                 data->has_error = True;
343                 return False;
344         }
345         free(id);
346         return True;
347 }
348
349 /* read a GeneralString from a ASN1 buffer */
350 BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
351 {
352         int len;
353         if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
354         len = asn1_tag_remaining(data);
355         *s = malloc(len+1);
356         if (! *s) {
357                 data->has_error = True;
358                 return False;
359         }
360         asn1_read(data, *s, len);
361         (*s)[len] = 0;
362         asn1_end_tag(data);
363         return !data->has_error;
364 }
365
366 /* read a octet string blob */
367 BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
368 {
369         int len;
370         if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
371         len = asn1_tag_remaining(data);
372         *blob = data_blob(NULL, len);
373         asn1_read(data, blob->data, len);
374         asn1_end_tag(data);
375         return !data->has_error;
376 }
377
378 /* read an interger */
379 BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
380 {
381         uint8 b;
382         *i = 0;
383         
384         if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
385         while (asn1_tag_remaining(data)>0) {
386                 *i = (*i << 8) + asn1_read_uint8(data, &b);
387         }
388         return asn1_end_tag(data);      
389         
390 }
391
392 /* check a enumarted value is correct */
393 BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
394 {
395         uint8 b;
396         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
397         asn1_read_uint8(data, &b);
398         asn1_end_tag(data);
399         return !data->has_error && (v == b);
400 }
401
402 /* check a enumarted value is correct */
403 BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
404 {
405         if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
406         asn1_write_uint8(data, v);
407         asn1_pop_tag(data);
408         return !data->has_error;
409 }