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