r20284: Simplify OID primitive BER parsing.
[samba.git] / source4 / 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 "libcli/util/asn_1.h"
23
24 /* free an asn1 structure */
25 void asn1_free(struct asn1_data *data)
26 {
27         talloc_free(data->data);
28         ZERO_STRUCTP(data);
29         data->has_error = True;
30 }
31
32 /* write to the ASN1 buffer, advancing the buffer pointer */
33 BOOL asn1_write(struct asn1_data *data, const void *p, int len)
34 {
35         if (data->has_error) return False;
36         if (data->length < data->ofs+len) {
37                 uint8_t *newp;
38                 newp = talloc_realloc(NULL, data->data, uint8_t, data->ofs+len);
39                 if (!newp) {
40                         asn1_free(data);
41                         data->has_error = True;
42                         return False;
43                 }
44                 data->data = newp;
45                 data->length = data->ofs+len;
46         }
47         memcpy(data->data + data->ofs, p, len);
48         data->ofs += len;
49         return True;
50 }
51
52 /* useful fn for writing a uint8_t */
53 BOOL asn1_write_uint8(struct asn1_data *data, uint8_t v)
54 {
55         return asn1_write(data, &v, 1);
56 }
57
58 /* push a tag onto the asn1 data buffer. Used for nested structures */
59 BOOL asn1_push_tag(struct asn1_data *data, uint8_t tag)
60 {
61         struct nesting *nesting;
62
63         asn1_write_uint8(data, tag);
64         nesting = talloc(NULL, struct nesting);
65         if (!nesting) {
66                 data->has_error = True;
67                 return False;
68         }
69
70         nesting->start = data->ofs;
71         nesting->next = data->nesting;
72         data->nesting = nesting;
73         return asn1_write_uint8(data, 0xff);
74 }
75
76 /* pop a tag */
77 BOOL asn1_pop_tag(struct asn1_data *data)
78 {
79         struct nesting *nesting;
80         size_t len;
81
82         nesting = data->nesting;
83
84         if (!nesting) {
85                 data->has_error = True;
86                 return False;
87         }
88         len = data->ofs - (nesting->start+1);
89         /* yes, this is ugly. We don't know in advance how many bytes the length
90            of a tag will take, so we assumed 1 byte. If we were wrong then we 
91            need to correct our mistake */
92         if (len > 0xFFFF) {
93                 data->data[nesting->start] = 0x83;
94                 if (!asn1_write_uint8(data, 0)) return False;
95                 if (!asn1_write_uint8(data, 0)) return False;
96                 if (!asn1_write_uint8(data, 0)) return False;
97                 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
98                 data->data[nesting->start+1] = (len>>16) & 0xFF;
99                 data->data[nesting->start+2] = (len>>8) & 0xFF;
100                 data->data[nesting->start+3] = len&0xff;
101         } else if (len > 255) {
102                 data->data[nesting->start] = 0x82;
103                 if (!asn1_write_uint8(data, 0)) return False;
104                 if (!asn1_write_uint8(data, 0)) return False;
105                 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
106                 data->data[nesting->start+1] = len>>8;
107                 data->data[nesting->start+2] = len&0xff;
108         } else if (len > 127) {
109                 data->data[nesting->start] = 0x81;
110                 if (!asn1_write_uint8(data, 0)) return False;
111                 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
112                 data->data[nesting->start+1] = len;
113         } else {
114                 data->data[nesting->start] = len;
115         }
116
117         data->nesting = nesting->next;
118         talloc_free(nesting);
119         return True;
120 }
121
122 /* "i" is the one's complement representation, as is the normal result of an
123  * implicit signed->unsigned conversion */
124
125 static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL negative)
126 {
127         uint8_t lowest = i & 0xFF;
128
129         i = i >> 8;
130         if (i != 0)
131                 if (!push_int_bigendian(data, i, negative))
132                         return False;
133
134         if (data->nesting->start+1 == data->ofs) {
135
136                 /* We did not write anything yet, looking at the highest
137                  * valued byte */
138
139                 if (negative) {
140                         /* Don't write leading 0xff's */
141                         if (lowest == 0xFF)
142                                 return True;
143
144                         if ((lowest & 0x80) == 0) {
145                                 /* The only exception for a leading 0xff is if
146                                  * the highest bit is 0, which would indicate
147                                  * a positive value */
148                                 if (!asn1_write_uint8(data, 0xff))
149                                         return False;
150                         }
151                 } else {
152                         if (lowest & 0x80) {
153                                 /* The highest bit of a positive integer is 1,
154                                  * this would indicate a negative number. Push
155                                  * a 0 to indicate a positive one */
156                                 if (!asn1_write_uint8(data, 0))
157                                         return False;
158                         }
159                 }
160         }
161
162         return asn1_write_uint8(data, lowest);
163 }
164
165 /* write an Integer without the tag framing. Needed for example for the LDAP
166  * Abandon Operation */
167
168 BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
169 {
170         if (i == -1) {
171                 /* -1 is special as it consists of all-0xff bytes. In
172                     push_int_bigendian this is the only case that is not
173                     properly handled, as all 0xff bytes would be handled as
174                     leading ones to be ignored. */
175                 return asn1_write_uint8(data, 0xff);
176         } else {
177                 return push_int_bigendian(data, i, i<0);
178         }
179 }
180
181
182 /* write an integer */
183 BOOL asn1_write_Integer(struct asn1_data *data, int i)
184 {
185         if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
186         if (!asn1_write_implicit_Integer(data, i)) return False;
187         return asn1_pop_tag(data);
188 }
189
190 BOOL ber_write_OID_String(DATA_BLOB *blob, const char *OID)
191 {
192         uint_t v, v2;
193         const char *p = (const char *)OID;
194         char *newp;
195         int i;
196
197         v = strtoul(p, &newp, 10);
198         if (newp[0] != '.') return False;
199         p = newp + 1;
200
201         v2 = strtoul(p, &newp, 10);
202         if (newp[0] != '.') return False;
203         p = newp + 1;
204
205         /*the ber representation can't use more space then the string one */
206         *blob = data_blob(NULL, strlen(OID));
207         if (!blob->data) return False;
208
209         blob->data[0] = 40*v + v2;
210
211         i = 1;
212         while (*p) {
213                 v = strtoul(p, &newp, 10);
214                 if (newp[0] == '.') {
215                         p = newp + 1;
216                 } else if (newp[0] == '\0') {
217                         p = newp;
218                 } else {
219                         data_blob_free(blob);
220                         return False;
221                 }
222                 if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
223                 if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
224                 if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
225                 if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
226                 blob->data[i++] = (v&0x7f);
227         }
228
229         blob->length = i;
230
231         return True;
232 }
233
234 /* write an object ID to a ASN1 buffer */
235 BOOL asn1_write_OID(struct asn1_data *data, const char *OID)
236 {
237         DATA_BLOB blob;
238
239         if (!asn1_push_tag(data, ASN1_OID)) return False;
240
241         if (!ber_write_OID_String(&blob, OID)) {
242                 data->has_error = True;
243                 return False;
244         }
245
246         if (!asn1_write(data, blob.data, blob.length)) {
247                 data->has_error = True;
248                 return False;
249         }
250         data_blob_free(&blob);
251         return asn1_pop_tag(data);
252 }
253
254 /* write an octet string */
255 BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
256 {
257         asn1_push_tag(data, ASN1_OCTET_STRING);
258         asn1_write(data, p, length);
259         asn1_pop_tag(data);
260         return !data->has_error;
261 }
262
263 /* write a LDAP string */
264 BOOL asn1_write_LDAPString(struct asn1_data *data, const char *s)
265 {
266         asn1_write(data, s, strlen(s));
267         return !data->has_error;
268 }
269
270 /* write a general string */
271 BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
272 {
273         asn1_push_tag(data, ASN1_GENERAL_STRING);
274         asn1_write_LDAPString(data, s);
275         asn1_pop_tag(data);
276         return !data->has_error;
277 }
278
279 BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
280 {
281         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
282         asn1_write(data, blob->data, blob->length);
283         asn1_pop_tag(data);
284         return !data->has_error;
285 }
286
287 /* write a BOOLEAN */
288 BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
289 {
290         asn1_push_tag(data, ASN1_BOOLEAN);
291         asn1_write_uint8(data, v ? 0xFF : 0);
292         asn1_pop_tag(data);
293         return !data->has_error;
294 }
295
296 BOOL asn1_read_BOOLEAN(struct asn1_data *data, BOOL *v)
297 {
298         uint8_t tmp = 0;
299         asn1_start_tag(data, ASN1_BOOLEAN);
300         asn1_read_uint8(data, &tmp);
301         if (tmp == 0xFF) {
302                 *v = True;
303         } else {
304                 *v = False;
305         }
306         asn1_end_tag(data);
307         return !data->has_error;
308 }
309
310 /* check a BOOLEAN */
311 BOOL asn1_check_BOOLEAN(struct asn1_data *data, BOOL v)
312 {
313         uint8_t b = 0;
314
315         asn1_read_uint8(data, &b);
316         if (b != ASN1_BOOLEAN) {
317                 data->has_error = True;
318                 return False;
319         }
320         asn1_read_uint8(data, &b);
321         if (b != v) {
322                 data->has_error = True;
323                 return False;
324         }
325         return !data->has_error;
326 }
327
328
329 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
330 BOOL asn1_load(struct asn1_data *data, DATA_BLOB blob)
331 {
332         ZERO_STRUCTP(data);
333         data->data = talloc_memdup(NULL, blob.data, blob.length);
334         if (!data->data) {
335                 data->has_error = True;
336                 return False;
337         }
338         data->length = blob.length;
339         return True;
340 }
341
342 /* Peek into an ASN1 buffer, not advancing the pointer */
343 BOOL asn1_peek(struct asn1_data *data, void *p, int len)
344 {
345         if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
346                 return False;
347
348         if (data->ofs + len > data->length) {
349                 /* we need to mark the buffer as consumed, so the caller knows
350                    this was an out of data error, and not a decode error */
351                 data->ofs = data->length;
352                 return False;
353         }
354
355         memcpy(p, data->data + data->ofs, len);
356         return True;
357 }
358
359 /* read from a ASN1 buffer, advancing the buffer pointer */
360 BOOL asn1_read(struct asn1_data *data, void *p, int len)
361 {
362         if (!asn1_peek(data, p, len)) {
363                 data->has_error = True;
364                 return False;
365         }
366
367         data->ofs += len;
368         return True;
369 }
370
371 /* read a uint8_t from a ASN1 buffer */
372 BOOL asn1_read_uint8(struct asn1_data *data, uint8_t *v)
373 {
374         return asn1_read(data, v, 1);
375 }
376
377 BOOL asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
378 {
379         return asn1_peek(data, v, 1);
380 }
381
382 BOOL asn1_peek_tag(struct asn1_data *data, uint8_t tag)
383 {
384         uint8_t b;
385
386         if (asn1_tag_remaining(data) <= 0) {
387                 return False;
388         }
389
390         if (!asn1_peek(data, &b, sizeof(b)))
391                 return False;
392
393         return (b == tag);
394 }
395
396 /* start reading a nested asn1 structure */
397 BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
398 {
399         uint8_t b;
400         struct nesting *nesting;
401         
402         if (!asn1_read_uint8(data, &b))
403                 return False;
404
405         if (b != tag) {
406                 data->has_error = True;
407                 return False;
408         }
409         nesting = talloc(NULL, struct nesting);
410         if (!nesting) {
411                 data->has_error = True;
412                 return False;
413         }
414
415         if (!asn1_read_uint8(data, &b)) {
416                 return False;
417         }
418
419         if (b & 0x80) {
420                 int n = b & 0x7f;
421                 if (!asn1_read_uint8(data, &b))
422                         return False;
423                 nesting->taglen = b;
424                 while (n > 1) {
425                         if (!asn1_read_uint8(data, &b)) 
426                                 return False;
427                         nesting->taglen = (nesting->taglen << 8) | b;
428                         n--;
429                 }
430         } else {
431                 nesting->taglen = b;
432         }
433         nesting->start = data->ofs;
434         nesting->next = data->nesting;
435         data->nesting = nesting;
436         if (asn1_tag_remaining(data) == -1) {
437                 return False;
438         }
439         return !data->has_error;
440 }
441
442 /* stop reading a tag */
443 BOOL asn1_end_tag(struct asn1_data *data)
444 {
445         struct nesting *nesting;
446
447         /* make sure we read it all */
448         if (asn1_tag_remaining(data) != 0) {
449                 data->has_error = True;
450                 return False;
451         }
452
453         nesting = data->nesting;
454
455         if (!nesting) {
456                 data->has_error = True;
457                 return False;
458         }
459
460         data->nesting = nesting->next;
461         talloc_free(nesting);
462         return True;
463 }
464
465 /* work out how many bytes are left in this nested tag */
466 int asn1_tag_remaining(struct asn1_data *data)
467 {
468         int remaining;
469         if (data->has_error) {
470                 return -1;
471         }
472
473         if (!data->nesting) {
474                 data->has_error = True;
475                 return -1;
476         }
477         remaining = data->nesting->taglen - (data->ofs - data->nesting->start);
478         if (remaining > (data->length - data->ofs)) {
479                 data->has_error = True;
480                 return -1;
481         }
482         return remaining;
483 }
484
485 /* read an object ID from a data blob */
486 BOOL ber_read_OID_String(DATA_BLOB blob, const char **OID)
487 {
488         int i;
489         uint8_t *b;
490         uint_t v;
491         char *tmp_oid = NULL;
492
493         if (blob.length < 2) return False;
494
495         b = blob.data;
496
497         tmp_oid = talloc_asprintf(NULL, "%u",  b[0]/40);
498         if (!tmp_oid) goto nomem;
499         tmp_oid = talloc_asprintf_append(tmp_oid, ".%u",  b[0]%40);
500         if (!tmp_oid) goto nomem;
501
502         for(i = 1, v = 0; i < blob.length; i++) {
503                 v = (v<<7) | (b[i]&0x7f);
504                 if ( ! (b[i] & 0x80)) {
505                         tmp_oid = talloc_asprintf_append(tmp_oid, ".%u",  v);
506                         v = 0;
507                 }
508                 if (!tmp_oid) goto nomem;
509         }
510
511         if (v != 0) {
512                 talloc_free(tmp_oid);
513                 return False;
514         }
515
516         *OID = tmp_oid;
517         return True;
518
519 nomem:  
520         return False;
521 }
522
523 /* read an object ID from a ASN1 buffer */
524 BOOL asn1_read_OID(struct asn1_data *data, const char **OID)
525 {
526         DATA_BLOB blob;
527         int len;
528
529         if (!asn1_start_tag(data, ASN1_OID)) return False;
530
531         len = asn1_tag_remaining(data);
532         if (len < 0) {
533                 data->has_error = True;
534                 return False;
535         }
536
537         blob = data_blob(NULL, len);
538         if (!blob.data) {
539                 data->has_error = True;
540                 return False;
541         }
542
543         asn1_read(data, blob.data, len);
544         asn1_end_tag(data);
545         if (data->has_error) {
546                 data_blob_free(&blob);
547                 return False;
548         }
549
550         if (!ber_read_OID_String(blob, OID)) {
551                 data->has_error = True;
552                 data_blob_free(&blob);
553                 return False;
554         }
555
556         data_blob_free(&blob);
557         return True;
558 }
559
560 /* check that the next object ID is correct */
561 BOOL asn1_check_OID(struct asn1_data *data, const char *OID)
562 {
563         const char *id;
564
565         if (!asn1_read_OID(data, &id)) return False;
566
567         if (strcmp(id, OID) != 0) {
568                 data->has_error = True;
569                 return False;
570         }
571         talloc_free(discard_const(id));
572         return True;
573 }
574
575 /* read a LDAPString from a ASN1 buffer */
576 BOOL asn1_read_LDAPString(struct asn1_data *data, char **s)
577 {
578         int len;
579         len = asn1_tag_remaining(data);
580         if (len < 0) {
581                 data->has_error = True;
582                 return False;
583         }
584         *s = talloc_size(NULL, len+1);
585         if (! *s) {
586                 data->has_error = True;
587                 return False;
588         }
589         asn1_read(data, *s, len);
590         (*s)[len] = 0;
591         return !data->has_error;
592 }
593
594
595 /* read a GeneralString from a ASN1 buffer */
596 BOOL asn1_read_GeneralString(struct asn1_data *data, char **s)
597 {
598         if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
599         if (!asn1_read_LDAPString(data, s)) return False;
600         return asn1_end_tag(data);
601 }
602
603
604 /* read a octet string blob */
605 BOOL asn1_read_OctetString(struct asn1_data *data, DATA_BLOB *blob)
606 {
607         int len;
608         ZERO_STRUCTP(blob);
609         if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
610         len = asn1_tag_remaining(data);
611         if (len < 0) {
612                 data->has_error = True;
613                 return False;
614         }
615         *blob = data_blob(NULL, len+1);
616         if (!blob->data) {
617                 data->has_error = True;
618                 return False;
619         }
620         asn1_read(data, blob->data, len);
621         asn1_end_tag(data);
622         blob->length--;
623         blob->data[len] = 0;
624         
625         if (data->has_error) {
626                 data_blob_free(blob);
627                 *blob = data_blob(NULL, 0);
628                 return False;
629         }
630         return True;
631 }
632
633 BOOL asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
634 {
635         int len;
636         ZERO_STRUCTP(blob);
637         if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return False;
638         len = asn1_tag_remaining(data);
639         if (len < 0) {
640                 data->has_error = True;
641                 return False;
642         }
643         *blob = data_blob(NULL, len);
644         if (!blob->data) {
645                 data->has_error = True;
646                 return False;
647         }
648         asn1_read(data, blob->data, len);
649         asn1_end_tag(data);
650         return !data->has_error;
651 }
652
653 /* read an interger without tag*/
654 BOOL asn1_read_implicit_Integer(struct asn1_data *data, int *i)
655 {
656         uint8_t b;
657         *i = 0;
658
659         while (!data->has_error && asn1_tag_remaining(data)>0) {
660                 if (!asn1_read_uint8(data, &b)) return False;
661                 *i = (*i << 8) + b;
662         }
663         return !data->has_error;        
664         
665 }
666
667 /* read an interger */
668 BOOL asn1_read_Integer(struct asn1_data *data, int *i)
669 {
670         *i = 0;
671
672         if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
673         if (!asn1_read_implicit_Integer(data, i)) return False;
674         return asn1_end_tag(data);      
675 }
676
677 /* read an interger */
678 BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
679 {
680         *v = 0;
681         
682         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
683         while (!data->has_error && asn1_tag_remaining(data)>0) {
684                 uint8_t b;
685                 asn1_read_uint8(data, &b);
686                 *v = (*v << 8) + b;
687         }
688         return asn1_end_tag(data);      
689 }
690
691 /* check a enumarted value is correct */
692 BOOL asn1_check_enumerated(struct asn1_data *data, int v)
693 {
694         uint8_t b;
695         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
696         asn1_read_uint8(data, &b);
697         asn1_end_tag(data);
698
699         if (v != b)
700                 data->has_error = False;
701
702         return !data->has_error;
703 }
704
705 /* write an enumarted value to the stream */
706 BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
707 {
708         if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
709         asn1_write_uint8(data, v);
710         asn1_pop_tag(data);
711         return !data->has_error;
712 }
713
714 /*
715   check if a ASN.1 blob is a full tag
716 */
717 NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
718 {
719         struct asn1_data asn1;
720         int size;
721
722         ZERO_STRUCT(asn1);
723         asn1.data = blob.data;
724         asn1.length = blob.length;
725         asn1_start_tag(&asn1, tag);
726         if (asn1.has_error) {
727                 talloc_free(asn1.nesting);
728                 return STATUS_MORE_ENTRIES;
729         }
730         size = asn1_tag_remaining(&asn1) + asn1.ofs;
731         talloc_free(asn1.nesting);
732
733         if (size > blob.length) {
734                 return STATUS_MORE_ENTRIES;
735         }               
736
737         *packet_size = size;
738         return NT_STATUS_OK;
739 }