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