r23037: actually fix the asn1 memory leak :-)
[Samba.git] / source / libcli / util / asn1.c
blob477887b96a636e74bfa4f84d2aa5877e53f47432
1 /*
2 Unix SMB/CIFS implementation.
3 simple SPNEGO routines
4 Copyright (C) Andrew Tridgell 2001
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.
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.
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.
21 #include "includes.h"
22 #include "libcli/util/asn_1.h"
24 /* allocate an asn1 structure */
25 struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
27 struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
28 if (ret == NULL) {
29 DEBUG(0,("asn1_init failed! out of memory\n"));
31 return ret;
34 /* free an asn1 structure */
35 void asn1_free(struct asn1_data *data)
37 talloc_free(data);
40 /* write to the ASN1 buffer, advancing the buffer pointer */
41 BOOL asn1_write(struct asn1_data *data, const void *p, int len)
43 if (data->has_error) return False;
44 if (data->length < data->ofs+len) {
45 uint8_t *newp;
46 newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
47 if (!newp) {
48 asn1_free(data);
49 data->has_error = True;
50 return False;
52 data->data = newp;
53 data->length = data->ofs+len;
55 memcpy(data->data + data->ofs, p, len);
56 data->ofs += len;
57 return True;
60 /* useful fn for writing a uint8_t */
61 BOOL asn1_write_uint8(struct asn1_data *data, uint8_t v)
63 return asn1_write(data, &v, 1);
66 /* push a tag onto the asn1 data buffer. Used for nested structures */
67 BOOL asn1_push_tag(struct asn1_data *data, uint8_t tag)
69 struct nesting *nesting;
71 asn1_write_uint8(data, tag);
72 nesting = talloc(data, struct nesting);
73 if (!nesting) {
74 data->has_error = True;
75 return False;
78 nesting->start = data->ofs;
79 nesting->next = data->nesting;
80 data->nesting = nesting;
81 return asn1_write_uint8(data, 0xff);
84 /* pop a tag */
85 BOOL asn1_pop_tag(struct asn1_data *data)
87 struct nesting *nesting;
88 size_t len;
90 nesting = data->nesting;
92 if (!nesting) {
93 data->has_error = True;
94 return False;
96 len = data->ofs - (nesting->start+1);
97 /* yes, this is ugly. We don't know in advance how many bytes the length
98 of a tag will take, so we assumed 1 byte. If we were wrong then we
99 need to correct our mistake */
100 if (len > 0xFFFFFF) {
101 data->data[nesting->start] = 0x84;
102 if (!asn1_write_uint8(data, 0)) return False;
103 if (!asn1_write_uint8(data, 0)) return False;
104 if (!asn1_write_uint8(data, 0)) return False;
105 if (!asn1_write_uint8(data, 0)) return False;
106 memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
107 data->data[nesting->start+1] = (len>>24) & 0xFF;
108 data->data[nesting->start+2] = (len>>16) & 0xFF;
109 data->data[nesting->start+3] = (len>>8) & 0xFF;
110 data->data[nesting->start+4] = len&0xff;
111 } else if (len > 0xFFFF) {
112 data->data[nesting->start] = 0x83;
113 if (!asn1_write_uint8(data, 0)) return False;
114 if (!asn1_write_uint8(data, 0)) return False;
115 if (!asn1_write_uint8(data, 0)) return False;
116 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
117 data->data[nesting->start+1] = (len>>16) & 0xFF;
118 data->data[nesting->start+2] = (len>>8) & 0xFF;
119 data->data[nesting->start+3] = len&0xff;
120 } else if (len > 255) {
121 data->data[nesting->start] = 0x82;
122 if (!asn1_write_uint8(data, 0)) return False;
123 if (!asn1_write_uint8(data, 0)) return False;
124 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
125 data->data[nesting->start+1] = len>>8;
126 data->data[nesting->start+2] = len&0xff;
127 } else if (len > 127) {
128 data->data[nesting->start] = 0x81;
129 if (!asn1_write_uint8(data, 0)) return False;
130 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
131 data->data[nesting->start+1] = len;
132 } else {
133 data->data[nesting->start] = len;
136 data->nesting = nesting->next;
137 talloc_free(nesting);
138 return True;
141 /* "i" is the one's complement representation, as is the normal result of an
142 * implicit signed->unsigned conversion */
144 static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL negative)
146 uint8_t lowest = i & 0xFF;
148 i = i >> 8;
149 if (i != 0)
150 if (!push_int_bigendian(data, i, negative))
151 return False;
153 if (data->nesting->start+1 == data->ofs) {
155 /* We did not write anything yet, looking at the highest
156 * valued byte */
158 if (negative) {
159 /* Don't write leading 0xff's */
160 if (lowest == 0xFF)
161 return True;
163 if ((lowest & 0x80) == 0) {
164 /* The only exception for a leading 0xff is if
165 * the highest bit is 0, which would indicate
166 * a positive value */
167 if (!asn1_write_uint8(data, 0xff))
168 return False;
170 } else {
171 if (lowest & 0x80) {
172 /* The highest bit of a positive integer is 1,
173 * this would indicate a negative number. Push
174 * a 0 to indicate a positive one */
175 if (!asn1_write_uint8(data, 0))
176 return False;
181 return asn1_write_uint8(data, lowest);
184 /* write an Integer without the tag framing. Needed for example for the LDAP
185 * Abandon Operation */
187 BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
189 if (i == -1) {
190 /* -1 is special as it consists of all-0xff bytes. In
191 push_int_bigendian this is the only case that is not
192 properly handled, as all 0xff bytes would be handled as
193 leading ones to be ignored. */
194 return asn1_write_uint8(data, 0xff);
195 } else {
196 return push_int_bigendian(data, i, i<0);
201 /* write an integer */
202 BOOL asn1_write_Integer(struct asn1_data *data, int i)
204 if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
205 if (!asn1_write_implicit_Integer(data, i)) return False;
206 return asn1_pop_tag(data);
209 BOOL ber_write_OID_String(DATA_BLOB *blob, const char *OID)
211 uint_t v, v2;
212 const char *p = (const char *)OID;
213 char *newp;
214 int i;
216 v = strtoul(p, &newp, 10);
217 if (newp[0] != '.') return False;
218 p = newp + 1;
220 v2 = strtoul(p, &newp, 10);
221 if (newp[0] != '.') return False;
222 p = newp + 1;
224 /*the ber representation can't use more space then the string one */
225 *blob = data_blob(NULL, strlen(OID));
226 if (!blob->data) return False;
228 blob->data[0] = 40*v + v2;
230 i = 1;
231 while (*p) {
232 v = strtoul(p, &newp, 10);
233 if (newp[0] == '.') {
234 p = newp + 1;
235 } else if (newp[0] == '\0') {
236 p = newp;
237 } else {
238 data_blob_free(blob);
239 return False;
241 if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
242 if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
243 if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
244 if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
245 blob->data[i++] = (v&0x7f);
248 blob->length = i;
250 return True;
253 /* write an object ID to a ASN1 buffer */
254 BOOL asn1_write_OID(struct asn1_data *data, const char *OID)
256 DATA_BLOB blob;
258 if (!asn1_push_tag(data, ASN1_OID)) return False;
260 if (!ber_write_OID_String(&blob, OID)) {
261 data->has_error = True;
262 return False;
265 if (!asn1_write(data, blob.data, blob.length)) {
266 data->has_error = True;
267 return False;
269 data_blob_free(&blob);
270 return asn1_pop_tag(data);
273 /* write an octet string */
274 BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
276 asn1_push_tag(data, ASN1_OCTET_STRING);
277 asn1_write(data, p, length);
278 asn1_pop_tag(data);
279 return !data->has_error;
282 /* write a LDAP string */
283 BOOL asn1_write_LDAPString(struct asn1_data *data, const char *s)
285 asn1_write(data, s, strlen(s));
286 return !data->has_error;
289 /* write a general string */
290 BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
292 asn1_push_tag(data, ASN1_GENERAL_STRING);
293 asn1_write_LDAPString(data, s);
294 asn1_pop_tag(data);
295 return !data->has_error;
298 BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
300 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
301 asn1_write(data, blob->data, blob->length);
302 asn1_pop_tag(data);
303 return !data->has_error;
306 /* write a BOOLEAN */
307 BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
309 asn1_push_tag(data, ASN1_BOOLEAN);
310 asn1_write_uint8(data, v ? 0xFF : 0);
311 asn1_pop_tag(data);
312 return !data->has_error;
315 BOOL asn1_read_BOOLEAN(struct asn1_data *data, BOOL *v)
317 uint8_t tmp = 0;
318 asn1_start_tag(data, ASN1_BOOLEAN);
319 asn1_read_uint8(data, &tmp);
320 if (tmp == 0xFF) {
321 *v = True;
322 } else {
323 *v = False;
325 asn1_end_tag(data);
326 return !data->has_error;
329 /* check a BOOLEAN */
330 BOOL asn1_check_BOOLEAN(struct asn1_data *data, BOOL v)
332 uint8_t b = 0;
334 asn1_read_uint8(data, &b);
335 if (b != ASN1_BOOLEAN) {
336 data->has_error = True;
337 return False;
339 asn1_read_uint8(data, &b);
340 if (b != v) {
341 data->has_error = True;
342 return False;
344 return !data->has_error;
348 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
349 BOOL asn1_load(struct asn1_data *data, DATA_BLOB blob)
351 ZERO_STRUCTP(data);
352 data->data = talloc_memdup(data, blob.data, blob.length);
353 if (!data->data) {
354 data->has_error = True;
355 return False;
357 data->length = blob.length;
358 return True;
361 /* Peek into an ASN1 buffer, not advancing the pointer */
362 BOOL asn1_peek(struct asn1_data *data, void *p, int len)
364 if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
365 return False;
367 if (data->ofs + len > data->length) {
368 /* we need to mark the buffer as consumed, so the caller knows
369 this was an out of data error, and not a decode error */
370 data->ofs = data->length;
371 return False;
374 memcpy(p, data->data + data->ofs, len);
375 return True;
378 /* read from a ASN1 buffer, advancing the buffer pointer */
379 BOOL asn1_read(struct asn1_data *data, void *p, int len)
381 if (!asn1_peek(data, p, len)) {
382 data->has_error = True;
383 return False;
386 data->ofs += len;
387 return True;
390 /* read a uint8_t from a ASN1 buffer */
391 BOOL asn1_read_uint8(struct asn1_data *data, uint8_t *v)
393 return asn1_read(data, v, 1);
396 BOOL asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
398 return asn1_peek(data, v, 1);
401 BOOL asn1_peek_tag(struct asn1_data *data, uint8_t tag)
403 uint8_t b;
405 if (asn1_tag_remaining(data) <= 0) {
406 return False;
409 if (!asn1_peek(data, &b, sizeof(b)))
410 return False;
412 return (b == tag);
415 /* start reading a nested asn1 structure */
416 BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
418 uint8_t b;
419 struct nesting *nesting;
421 if (!asn1_read_uint8(data, &b))
422 return False;
424 if (b != tag) {
425 data->has_error = True;
426 return False;
428 nesting = talloc(data, struct nesting);
429 if (!nesting) {
430 data->has_error = True;
431 return False;
434 if (!asn1_read_uint8(data, &b)) {
435 return False;
438 if (b & 0x80) {
439 int n = b & 0x7f;
440 if (!asn1_read_uint8(data, &b))
441 return False;
442 nesting->taglen = b;
443 while (n > 1) {
444 if (!asn1_read_uint8(data, &b))
445 return False;
446 nesting->taglen = (nesting->taglen << 8) | b;
447 n--;
449 } else {
450 nesting->taglen = b;
452 nesting->start = data->ofs;
453 nesting->next = data->nesting;
454 data->nesting = nesting;
455 if (asn1_tag_remaining(data) == -1) {
456 return False;
458 return !data->has_error;
461 /* stop reading a tag */
462 BOOL asn1_end_tag(struct asn1_data *data)
464 struct nesting *nesting;
466 /* make sure we read it all */
467 if (asn1_tag_remaining(data) != 0) {
468 data->has_error = True;
469 return False;
472 nesting = data->nesting;
474 if (!nesting) {
475 data->has_error = True;
476 return False;
479 data->nesting = nesting->next;
480 talloc_free(nesting);
481 return True;
484 /* work out how many bytes are left in this nested tag */
485 int asn1_tag_remaining(struct asn1_data *data)
487 int remaining;
488 if (data->has_error) {
489 return -1;
492 if (!data->nesting) {
493 data->has_error = True;
494 return -1;
496 remaining = data->nesting->taglen - (data->ofs - data->nesting->start);
497 if (remaining > (data->length - data->ofs)) {
498 data->has_error = True;
499 return -1;
501 return remaining;
504 /* read an object ID from a data blob */
505 BOOL ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID)
507 int i;
508 uint8_t *b;
509 uint_t v;
510 char *tmp_oid = NULL;
512 if (blob.length < 2) return False;
514 b = blob.data;
516 tmp_oid = talloc_asprintf(mem_ctx, "%u", b[0]/40);
517 if (!tmp_oid) goto nomem;
518 tmp_oid = talloc_asprintf_append(tmp_oid, ".%u", b[0]%40);
519 if (!tmp_oid) goto nomem;
521 for(i = 1, v = 0; i < blob.length; i++) {
522 v = (v<<7) | (b[i]&0x7f);
523 if ( ! (b[i] & 0x80)) {
524 tmp_oid = talloc_asprintf_append(tmp_oid, ".%u", v);
525 v = 0;
527 if (!tmp_oid) goto nomem;
530 if (v != 0) {
531 talloc_free(tmp_oid);
532 return False;
535 *OID = tmp_oid;
536 return True;
538 nomem:
539 return False;
542 /* read an object ID from a ASN1 buffer */
543 BOOL asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, const char **OID)
545 DATA_BLOB blob;
546 int len;
548 if (!asn1_start_tag(data, ASN1_OID)) return False;
550 len = asn1_tag_remaining(data);
551 if (len < 0) {
552 data->has_error = True;
553 return False;
556 blob = data_blob(NULL, len);
557 if (!blob.data) {
558 data->has_error = True;
559 return False;
562 asn1_read(data, blob.data, len);
563 asn1_end_tag(data);
564 if (data->has_error) {
565 data_blob_free(&blob);
566 return False;
569 if (!ber_read_OID_String(mem_ctx, blob, OID)) {
570 data->has_error = True;
571 data_blob_free(&blob);
572 return False;
575 data_blob_free(&blob);
576 return True;
579 /* check that the next object ID is correct */
580 BOOL asn1_check_OID(struct asn1_data *data, const char *OID)
582 const char *id;
584 if (!asn1_read_OID(data, data, &id)) return False;
586 if (strcmp(id, OID) != 0) {
587 talloc_free(discard_const(id));
588 data->has_error = True;
589 return False;
591 talloc_free(discard_const(id));
592 return True;
595 /* read a LDAPString from a ASN1 buffer */
596 BOOL asn1_read_LDAPString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
598 int len;
599 len = asn1_tag_remaining(data);
600 if (len < 0) {
601 data->has_error = True;
602 return False;
604 *s = talloc_size(mem_ctx, len+1);
605 if (! *s) {
606 data->has_error = True;
607 return False;
609 asn1_read(data, *s, len);
610 (*s)[len] = 0;
611 return !data->has_error;
615 /* read a GeneralString from a ASN1 buffer */
616 BOOL asn1_read_GeneralString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
618 if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
619 if (!asn1_read_LDAPString(data, mem_ctx, s)) return False;
620 return asn1_end_tag(data);
624 /* read a octet string blob */
625 BOOL asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
627 int len;
628 ZERO_STRUCTP(blob);
629 if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
630 len = asn1_tag_remaining(data);
631 if (len < 0) {
632 data->has_error = True;
633 return False;
635 *blob = data_blob_talloc(mem_ctx, NULL, len+1);
636 if (!blob->data) {
637 data->has_error = True;
638 return False;
640 asn1_read(data, blob->data, len);
641 asn1_end_tag(data);
642 blob->length--;
643 blob->data[len] = 0;
645 if (data->has_error) {
646 data_blob_free(blob);
647 *blob = data_blob(NULL, 0);
648 return False;
650 return True;
653 BOOL asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
655 int len;
656 ZERO_STRUCTP(blob);
657 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return False;
658 len = asn1_tag_remaining(data);
659 if (len < 0) {
660 data->has_error = True;
661 return False;
663 *blob = data_blob(NULL, len);
664 if ((len != 0) && (!blob->data)) {
665 data->has_error = True;
666 return False;
668 asn1_read(data, blob->data, len);
669 asn1_end_tag(data);
670 return !data->has_error;
673 /* read an interger without tag*/
674 BOOL asn1_read_implicit_Integer(struct asn1_data *data, int *i)
676 uint8_t b;
677 *i = 0;
679 while (!data->has_error && asn1_tag_remaining(data)>0) {
680 if (!asn1_read_uint8(data, &b)) return False;
681 *i = (*i << 8) + b;
683 return !data->has_error;
687 /* read an interger */
688 BOOL asn1_read_Integer(struct asn1_data *data, int *i)
690 *i = 0;
692 if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
693 if (!asn1_read_implicit_Integer(data, i)) return False;
694 return asn1_end_tag(data);
697 /* read an interger */
698 BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
700 *v = 0;
702 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
703 while (!data->has_error && asn1_tag_remaining(data)>0) {
704 uint8_t b;
705 asn1_read_uint8(data, &b);
706 *v = (*v << 8) + b;
708 return asn1_end_tag(data);
711 /* check a enumarted value is correct */
712 BOOL asn1_check_enumerated(struct asn1_data *data, int v)
714 uint8_t b;
715 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
716 asn1_read_uint8(data, &b);
717 asn1_end_tag(data);
719 if (v != b)
720 data->has_error = False;
722 return !data->has_error;
725 /* write an enumarted value to the stream */
726 BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
728 if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
729 asn1_write_uint8(data, v);
730 asn1_pop_tag(data);
731 return !data->has_error;
735 check if a ASN.1 blob is a full tag
737 NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
739 struct asn1_data *asn1 = asn1_init(NULL);
740 int size;
742 NT_STATUS_HAVE_NO_MEMORY(asn1);
744 asn1->data = blob.data;
745 asn1->length = blob.length;
746 asn1_start_tag(asn1, tag);
747 if (asn1->has_error) {
748 talloc_free(asn1);
749 return STATUS_MORE_ENTRIES;
751 size = asn1_tag_remaining(asn1) + asn1->ofs;
753 talloc_free(asn1);
755 if (size > blob.length) {
756 return STATUS_MORE_ENTRIES;
759 *packet_size = size;
760 return NT_STATUS_OK;