r7941: fixed handling of ASN.1 objects bigger than 64k
[ira/wip.git] / source / libcli / util / 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "asn_1.h"
23
24 /* free an asn1 structure */
25 void asn1_free(struct asn1_data *data)
26 {
27         talloc_free(data->data);
28 }
29
30 /* write to the ASN1 buffer, advancing the buffer pointer */
31 BOOL asn1_write(struct 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_t *newp;
36                 newp = talloc_realloc(NULL, data->data, uint8_t, data->ofs+len);
37                 if (!newp) {
38                         asn1_free(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_t */
51 BOOL asn1_write_uint8(struct asn1_data *data, uint8_t 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(struct asn1_data *data, uint8_t tag)
58 {
59         struct nesting *nesting;
60
61         asn1_write_uint8(data, tag);
62         nesting = talloc(NULL, 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(struct 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 > 0xFFFF) {
91                 data->data[nesting->start] = 0x83;
92                 if (!asn1_write_uint8(data, 0)) return False;
93                 if (!asn1_write_uint8(data, 0)) return False;
94                 if (!asn1_write_uint8(data, 0)) return False;
95                 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
96                 data->data[nesting->start+1] = (len>>16) & 0xFF;
97                 data->data[nesting->start+2] = (len>>8) & 0xFF;
98                 data->data[nesting->start+3] = len&0xff;
99         } else if (len > 255) {
100                 data->data[nesting->start] = 0x82;
101                 if (!asn1_write_uint8(data, 0)) return False;
102                 if (!asn1_write_uint8(data, 0)) return False;
103                 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
104                 data->data[nesting->start+1] = len>>8;
105                 data->data[nesting->start+2] = len&0xff;
106         } else if (len > 127) {
107                 data->data[nesting->start] = 0x81;
108                 if (!asn1_write_uint8(data, 0)) return False;
109                 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
110                 data->data[nesting->start+1] = len;
111         } else {
112                 data->data[nesting->start] = len;
113         }
114
115         data->nesting = nesting->next;
116         talloc_free(nesting);
117         return True;
118 }
119
120 /* "i" is the one's complement representation, as is the normal result of an
121  * implicit signed->unsigned conversion */
122
123 static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL negative)
124 {
125         uint8_t lowest = i & 0xFF;
126
127         i = i >> 8;
128         if (i != 0)
129                 if (!push_int_bigendian(data, i, negative))
130                         return False;
131
132         if (data->nesting->start+1 == data->ofs) {
133
134                 /* We did not write anything yet, looking at the highest
135                  * valued byte */
136
137                 if (negative) {
138                         /* Don't write leading 0xff's */
139                         if (lowest == 0xFF)
140                                 return True;
141
142                         if ((lowest & 0x80) == 0) {
143                                 /* The only exception for a leading 0xff is if
144                                  * the highest bit is 0, which would indicate
145                                  * a positive value */
146                                 if (!asn1_write_uint8(data, 0xff))
147                                         return False;
148                         }
149                 } else {
150                         if (lowest & 0x80) {
151                                 /* The highest bit of a positive integer is 1,
152                                  * this would indicate a negative number. Push
153                                  * a 0 to indicate a positive one */
154                                 if (!asn1_write_uint8(data, 0))
155                                         return False;
156                         }
157                 }
158         }
159
160         return asn1_write_uint8(data, lowest);
161 }
162
163 /* write an Integer without the tag framing. Needed for example for the LDAP
164  * Abandon Operation */
165
166 BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
167 {
168         if (i == -1) {
169                 /* -1 is special as it consists of all-0xff bytes. In
170                     push_int_bigendian this is the only case that is not
171                     properly handled, as all 0xff bytes would be handled as
172                     leading ones to be ignored. */
173                 return asn1_write_uint8(data, 0xff);
174         } else {
175                 return push_int_bigendian(data, i, i<0);
176         }
177 }
178
179
180 /* write an integer */
181 BOOL asn1_write_Integer(struct asn1_data *data, int i)
182 {
183         if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
184         if (!asn1_write_implicit_Integer(data, i)) return False;
185         return asn1_pop_tag(data);
186 }
187
188 /* write an object ID to a ASN1 buffer */
189 BOOL asn1_write_OID(struct asn1_data *data, const char *OID)
190 {
191         uint_t v, v2;
192         const char *p = (const char *)OID;
193         char *newp;
194
195         if (!asn1_push_tag(data, ASN1_OID))
196                 return False;
197         v = strtol(p, &newp, 10);
198         p = newp;
199         v2 = strtol(p, &newp, 10);
200         p = newp;
201         if (!asn1_write_uint8(data, 40*v + v2))
202                 return False;
203
204         while (*p) {
205                 v = strtol(p, &newp, 10);
206                 p = newp;
207                 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
208                 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
209                 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
210                 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
211                 if (!asn1_write_uint8(data, v&0x7f))
212                         return False;
213         }
214         return asn1_pop_tag(data);
215 }
216
217 /* write an octet string */
218 BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
219 {
220         asn1_push_tag(data, ASN1_OCTET_STRING);
221         asn1_write(data, p, length);
222         asn1_pop_tag(data);
223         return !data->has_error;
224 }
225
226 /* write a LDAP string */
227 BOOL asn1_write_LDAPString(struct asn1_data *data, const char *s)
228 {
229         asn1_write(data, s, strlen(s));
230         return !data->has_error;
231 }
232
233 /* write a general string */
234 BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
235 {
236         asn1_push_tag(data, ASN1_GENERAL_STRING);
237         asn1_write_LDAPString(data, s);
238         asn1_pop_tag(data);
239         return !data->has_error;
240 }
241
242 BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
243 {
244         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
245         asn1_write(data, blob->data, blob->length);
246         asn1_pop_tag(data);
247         return !data->has_error;
248 }
249
250 /* write a BOOLEAN */
251 BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
252 {
253         asn1_push_tag(data, ASN1_BOOLEAN);
254         asn1_write_uint8(data, v ? 0xFF : 0);
255         asn1_pop_tag(data);
256         return !data->has_error;
257 }
258
259 BOOL asn1_read_BOOLEAN(struct asn1_data *data, BOOL *v)
260 {
261         uint8_t tmp = 0;
262         asn1_start_tag(data, ASN1_BOOLEAN);
263         asn1_read_uint8(data, &tmp);
264         if (tmp == 0xFF) {
265                 *v = True;
266         } else {
267                 *v = False;
268         }
269         asn1_end_tag(data);
270         return !data->has_error;
271 }
272
273 /* check a BOOLEAN */
274 BOOL asn1_check_BOOLEAN(struct asn1_data *data, BOOL v)
275 {
276         uint8_t b = 0;
277
278         asn1_read_uint8(data, &b);
279         if (b != ASN1_BOOLEAN) {
280                 data->has_error = True;
281                 return False;
282         }
283         asn1_read_uint8(data, &b);
284         if (b != v) {
285                 data->has_error = True;
286                 return False;
287         }
288         return !data->has_error;
289 }
290
291
292 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
293 BOOL asn1_load(struct asn1_data *data, DATA_BLOB blob)
294 {
295         ZERO_STRUCTP(data);
296         data->data = talloc_memdup(NULL, blob.data, blob.length);
297         if (!data->data) {
298                 data->has_error = True;
299                 return False;
300         }
301         data->length = blob.length;
302         return True;
303 }
304
305 /* Peek into an ASN1 buffer, not advancing the pointer */
306 BOOL asn1_peek(struct asn1_data *data, void *p, int len)
307 {
308         if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
309                 return False;
310
311         if (data->ofs + len > data->length) {
312                 /* we need to mark the buffer as consumed, so the caller knows
313                    this was an out of data error, and not a decode error */
314                 data->ofs = data->length;
315                 return False;
316         }
317
318         memcpy(p, data->data + data->ofs, len);
319         return True;
320 }
321
322 /* read from a ASN1 buffer, advancing the buffer pointer */
323 BOOL asn1_read(struct asn1_data *data, void *p, int len)
324 {
325         if (!asn1_peek(data, p, len)) {
326                 data->has_error = True;
327                 return False;
328         }
329
330         data->ofs += len;
331         return True;
332 }
333
334 /* read a uint8_t from a ASN1 buffer */
335 BOOL asn1_read_uint8(struct asn1_data *data, uint8_t *v)
336 {
337         return asn1_read(data, v, 1);
338 }
339
340 BOOL asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
341 {
342         return asn1_peek(data, v, 1);
343 }
344
345 BOOL asn1_peek_tag(struct asn1_data *data, uint8_t tag)
346 {
347         uint8_t b;
348
349         if (asn1_tag_remaining(data) <= 0) {
350                 return False;
351         }
352
353         if (!asn1_peek(data, &b, sizeof(b)))
354                 return False;
355
356         return (b == tag);
357 }
358
359 /* start reading a nested asn1 structure */
360 BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
361 {
362         uint8_t b;
363         struct nesting *nesting;
364         
365         if (!asn1_read_uint8(data, &b))
366                 return False;
367
368         if (b != tag) {
369                 data->has_error = True;
370                 return False;
371         }
372         nesting = talloc(NULL, struct nesting);
373         if (!nesting) {
374                 data->has_error = True;
375                 return False;
376         }
377
378         if (!asn1_read_uint8(data, &b)) {
379                 return False;
380         }
381
382         if (b & 0x80) {
383                 int n = b & 0x7f;
384                 if (!asn1_read_uint8(data, &b))
385                         return False;
386                 nesting->taglen = b;
387                 while (n > 1) {
388                         if (!asn1_read_uint8(data, &b)) 
389                                 return False;
390                         nesting->taglen = (nesting->taglen << 8) | b;
391                         n--;
392                 }
393         } else {
394                 nesting->taglen = b;
395         }
396         nesting->start = data->ofs;
397         nesting->next = data->nesting;
398         data->nesting = nesting;
399         return !data->has_error;
400 }
401
402
403 /* stop reading a tag */
404 BOOL asn1_end_tag(struct asn1_data *data)
405 {
406         struct nesting *nesting;
407
408         /* make sure we read it all */
409         if (asn1_tag_remaining(data) != 0) {
410                 data->has_error = True;
411                 return False;
412         }
413
414         nesting = data->nesting;
415
416         if (!nesting) {
417                 data->has_error = True;
418                 return False;
419         }
420
421         data->nesting = nesting->next;
422         talloc_free(nesting);
423         return True;
424 }
425
426 /* work out how many bytes are left in this nested tag */
427 int asn1_tag_remaining(struct asn1_data *data)
428 {
429         if (!data->nesting) {
430                 data->has_error = True;
431                 return -1;
432         }
433         return data->nesting->taglen - (data->ofs - data->nesting->start);
434 }
435
436 /* read an object ID from a ASN1 buffer */
437 BOOL asn1_read_OID(struct asn1_data *data, const char **OID)
438 {
439         uint8_t b;
440         char *tmp_oid = NULL;
441
442         if (!asn1_start_tag(data, ASN1_OID)) return False;
443         asn1_read_uint8(data, &b);
444
445         tmp_oid = talloc_asprintf(NULL, "%u",  b/40);
446         tmp_oid = talloc_asprintf_append(tmp_oid, " %u",  b%40);
447
448         while (!data->has_error && asn1_tag_remaining(data) > 0) {
449                 uint_t v = 0;
450                 do {
451                         asn1_read_uint8(data, &b);
452                         v = (v<<7) | (b&0x7f);
453                 } while (!data->has_error && (b & 0x80));
454                 tmp_oid = talloc_asprintf_append(tmp_oid, " %u",  v);
455         }
456
457         asn1_end_tag(data);
458
459         *OID = talloc_strdup(NULL, tmp_oid);
460         talloc_free(tmp_oid);
461
462         return (*OID && !data->has_error);
463 }
464
465 /* check that the next object ID is correct */
466 BOOL asn1_check_OID(struct asn1_data *data, const char *OID)
467 {
468         const char *id;
469
470         if (!asn1_read_OID(data, &id)) return False;
471
472         if (strcmp(id, OID) != 0) {
473                 data->has_error = True;
474                 return False;
475         }
476         talloc_free(discard_const(id));
477         return True;
478 }
479
480 /* read a LDAPString from a ASN1 buffer */
481 BOOL asn1_read_LDAPString(struct asn1_data *data, char **s)
482 {
483         int len;
484         len = asn1_tag_remaining(data);
485         if (len < 0) {
486                 data->has_error = True;
487                 return False;
488         }
489         *s = talloc_size(NULL, len+1);
490         if (! *s) {
491                 data->has_error = True;
492                 return False;
493         }
494         asn1_read(data, *s, len);
495         (*s)[len] = 0;
496         return !data->has_error;
497 }
498
499
500 /* read a GeneralString from a ASN1 buffer */
501 BOOL asn1_read_GeneralString(struct asn1_data *data, char **s)
502 {
503         if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
504         if (!asn1_read_LDAPString(data, s)) return False;
505         return asn1_end_tag(data);
506 }
507
508
509 /* read a octet string blob */
510 BOOL asn1_read_OctetString(struct asn1_data *data, DATA_BLOB *blob)
511 {
512         int len;
513         ZERO_STRUCTP(blob);
514         if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
515         len = asn1_tag_remaining(data);
516         if (len < 0) {
517                 data->has_error = True;
518                 return False;
519         }
520         *blob = data_blob(NULL, len+1);
521         asn1_read(data, blob->data, len);
522         asn1_end_tag(data);
523         blob->length--;
524         blob->data[len] = 0;
525         
526         if (data->has_error) {
527                 data_blob_free(blob);
528                 *blob = data_blob(NULL, 0);
529                 return False;
530         }
531         return True;
532 }
533
534 BOOL asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
535 {
536         int len;
537         ZERO_STRUCTP(blob);
538         if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return False;
539         len = asn1_tag_remaining(data);
540         if (len < 0) {
541                 data->has_error = True;
542                 return False;
543         }
544         *blob = data_blob(NULL, len);
545         asn1_read(data, blob->data, len);
546         asn1_end_tag(data);
547         return !data->has_error;
548 }
549
550 /* read an interger without tag*/
551 BOOL asn1_read_implicit_Integer(struct asn1_data *data, int *i)
552 {
553         uint8_t b;
554         *i = 0;
555
556         while (!data->has_error && asn1_tag_remaining(data)>0) {
557                 if (!asn1_read_uint8(data, &b)) return False;
558                 *i = (*i << 8) + b;
559         }
560         return !data->has_error;        
561         
562 }
563
564 /* read an interger */
565 BOOL asn1_read_Integer(struct asn1_data *data, int *i)
566 {
567         *i = 0;
568
569         if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
570         if (!asn1_read_implicit_Integer(data, i)) return False;
571         return asn1_end_tag(data);      
572 }
573
574 /* read an interger */
575 BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
576 {
577         *v = 0;
578         
579         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
580         while (!data->has_error && asn1_tag_remaining(data)>0) {
581                 uint8_t b;
582                 asn1_read_uint8(data, &b);
583                 *v = (*v << 8) + b;
584         }
585         return asn1_end_tag(data);      
586 }
587
588 /* check a enumarted value is correct */
589 BOOL asn1_check_enumerated(struct asn1_data *data, int v)
590 {
591         uint8_t b;
592         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
593         asn1_read_uint8(data, &b);
594         asn1_end_tag(data);
595
596         if (v != b)
597                 data->has_error = False;
598
599         return !data->has_error;
600 }
601
602 /* write an enumarted value to the stream */
603 BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
604 {
605         if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
606         asn1_write_uint8(data, v);
607         asn1_pop_tag(data);
608         return !data->has_error;
609 }