r26694: asn1: Fix header and some typo's.
[samba.git] / source4 / libcli / util / asn1.c
index 01c869dc1724618e713725f45865ddb1656eef97..aad55382d9b31613546ce7a150a99e4f5cd618ec 100644 (file)
@@ -1,11 +1,11 @@
 /* 
    Unix SMB/CIFS implementation.
-   simple SPNEGO routines
+   simple ASN1 routines
    Copyright (C) Andrew Tridgell 2001
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "libcli/util/asn_1.h"
 
+/* allocate an asn1 structure */
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
+{
+       struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
+       if (ret == NULL) {
+               DEBUG(0,("asn1_init failed! out of memory\n"));
+       }
+       return ret;
+}
+
 /* free an asn1 structure */
 void asn1_free(struct asn1_data *data)
 {
-       talloc_free(data->data);
+       talloc_free(data);
 }
 
 /* write to the ASN1 buffer, advancing the buffer pointer */
-BOOL asn1_write(struct asn1_data *data, const void *p, int len)
+bool asn1_write(struct asn1_data *data, const void *p, int len)
 {
-       if (data->has_error) return False;
+       if (data->has_error) return false;
        if (data->length < data->ofs+len) {
                uint8_t *newp;
-               newp = talloc_realloc(NULL, data->data, uint8_t, data->ofs+len);
+               newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
                if (!newp) {
                        asn1_free(data);
-                       data->has_error = True;
-                       return False;
+                       data->has_error = true;
+                       return false;
                }
                data->data = newp;
                data->length = data->ofs+len;
        }
        memcpy(data->data + data->ofs, p, len);
        data->ofs += len;
-       return True;
+       return true;
 }
 
 /* useful fn for writing a uint8_t */
-BOOL asn1_write_uint8(struct asn1_data *data, uint8_t v)
+bool asn1_write_uint8(struct asn1_data *data, uint8_t v)
 {
        return asn1_write(data, &v, 1);
 }
 
 /* push a tag onto the asn1 data buffer. Used for nested structures */
-BOOL asn1_push_tag(struct asn1_data *data, uint8_t tag)
+bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
 {
        struct nesting *nesting;
 
        asn1_write_uint8(data, tag);
-       nesting = talloc(NULL, struct nesting);
+       nesting = talloc(data, struct nesting);
        if (!nesting) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
 
        nesting->start = data->ofs;
@@ -72,7 +81,7 @@ BOOL asn1_push_tag(struct asn1_data *data, uint8_t tag)
 }
 
 /* pop a tag */
-BOOL asn1_pop_tag(struct asn1_data *data)
+bool asn1_pop_tag(struct asn1_data *data)
 {
        struct nesting *nesting;
        size_t len;
@@ -80,32 +89,43 @@ BOOL asn1_pop_tag(struct asn1_data *data)
        nesting = data->nesting;
 
        if (!nesting) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        len = data->ofs - (nesting->start+1);
        /* yes, this is ugly. We don't know in advance how many bytes the length
           of a tag will take, so we assumed 1 byte. If we were wrong then we 
           need to correct our mistake */
-       if (len > 0xFFFF) {
+       if (len > 0xFFFFFF) {
+               data->data[nesting->start] = 0x84;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
+               memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
+               data->data[nesting->start+1] = (len>>24) & 0xFF;
+               data->data[nesting->start+2] = (len>>16) & 0xFF;
+               data->data[nesting->start+3] = (len>>8) & 0xFF;
+               data->data[nesting->start+4] = len&0xff;
+       } else if (len > 0xFFFF) {
                data->data[nesting->start] = 0x83;
-               if (!asn1_write_uint8(data, 0)) return False;
-               if (!asn1_write_uint8(data, 0)) return False;
-               if (!asn1_write_uint8(data, 0)) return False;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
                memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
                data->data[nesting->start+1] = (len>>16) & 0xFF;
                data->data[nesting->start+2] = (len>>8) & 0xFF;
                data->data[nesting->start+3] = len&0xff;
        } else if (len > 255) {
                data->data[nesting->start] = 0x82;
-               if (!asn1_write_uint8(data, 0)) return False;
-               if (!asn1_write_uint8(data, 0)) return False;
+               if (!asn1_write_uint8(data, 0)) return false;
+               if (!asn1_write_uint8(data, 0)) return false;
                memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
                data->data[nesting->start+1] = len>>8;
                data->data[nesting->start+2] = len&0xff;
        } else if (len > 127) {
                data->data[nesting->start] = 0x81;
-               if (!asn1_write_uint8(data, 0)) return False;
+               if (!asn1_write_uint8(data, 0)) return false;
                memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
                data->data[nesting->start+1] = len;
        } else {
@@ -114,20 +134,20 @@ BOOL asn1_pop_tag(struct asn1_data *data)
 
        data->nesting = nesting->next;
        talloc_free(nesting);
-       return True;
+       return true;
 }
 
 /* "i" is the one's complement representation, as is the normal result of an
  * implicit signed->unsigned conversion */
 
-static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL negative)
+static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool negative)
 {
        uint8_t lowest = i & 0xFF;
 
        i = i >> 8;
        if (i != 0)
                if (!push_int_bigendian(data, i, negative))
-                       return False;
+                       return false;
 
        if (data->nesting->start+1 == data->ofs) {
 
@@ -137,14 +157,14 @@ static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL nega
                if (negative) {
                        /* Don't write leading 0xff's */
                        if (lowest == 0xFF)
-                               return True;
+                               return true;
 
                        if ((lowest & 0x80) == 0) {
                                /* The only exception for a leading 0xff is if
                                 * the highest bit is 0, which would indicate
                                 * a positive value */
                                if (!asn1_write_uint8(data, 0xff))
-                                       return False;
+                                       return false;
                        }
                } else {
                        if (lowest & 0x80) {
@@ -152,7 +172,7 @@ static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL nega
                                 * this would indicate a negative number. Push
                                 * a 0 to indicate a positive one */
                                if (!asn1_write_uint8(data, 0))
-                                       return False;
+                                       return false;
                        }
                }
        }
@@ -163,7 +183,7 @@ static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL nega
 /* write an Integer without the tag framing. Needed for example for the LDAP
  * Abandon Operation */
 
-BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
+bool asn1_write_implicit_Integer(struct asn1_data *data, int i)
 {
        if (i == -1) {
                /* -1 is special as it consists of all-0xff bytes. In
@@ -178,44 +198,79 @@ BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
 
 
 /* write an integer */
-BOOL asn1_write_Integer(struct asn1_data *data, int i)
+bool asn1_write_Integer(struct asn1_data *data, int i)
 {
-       if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
-       if (!asn1_write_implicit_Integer(data, i)) return False;
+       if (!asn1_push_tag(data, ASN1_INTEGER)) return false;
+       if (!asn1_write_implicit_Integer(data, i)) return false;
        return asn1_pop_tag(data);
 }
 
-/* write an object ID to a ASN1 buffer */
-BOOL asn1_write_OID(struct asn1_data *data, const char *OID)
+bool ber_write_OID_String(DATA_BLOB *blob, const char *OID)
 {
        uint_t v, v2;
        const char *p = (const char *)OID;
        char *newp;
+       int i;
+
+       v = strtoul(p, &newp, 10);
+       if (newp[0] != '.') return false;
+       p = newp + 1;
+
+       v2 = strtoul(p, &newp, 10);
+       if (newp[0] != '.') return false;
+       p = newp + 1;
 
-       if (!asn1_push_tag(data, ASN1_OID))
-               return False;
-       v = strtol(p, &newp, 10);
-       p = newp;
-       v2 = strtol(p, &newp, 10);
-       p = newp;
-       if (!asn1_write_uint8(data, 40*v + v2))
-               return False;
+       /*the ber representation can't use more space then the string one */
+       *blob = data_blob(NULL, strlen(OID));
+       if (!blob->data) return false;
 
+       blob->data[0] = 40*v + v2;
+
+       i = 1;
        while (*p) {
-               v = strtol(p, &newp, 10);
-               p = newp;
-               if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
-               if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
-               if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
-               if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
-               if (!asn1_write_uint8(data, v&0x7f))
-                       return False;
+               v = strtoul(p, &newp, 10);
+               if (newp[0] == '.') {
+                       p = newp + 1;
+               } else if (newp[0] == '\0') {
+                       p = newp;
+               } else {
+                       data_blob_free(blob);
+                       return false;
+               }
+               if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
+               if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
+               if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
+               if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
+               blob->data[i++] = (v&0x7f);
        }
+
+       blob->length = i;
+
+       return true;
+}
+
+/* write an object ID to a ASN1 buffer */
+bool asn1_write_OID(struct asn1_data *data, const char *OID)
+{
+       DATA_BLOB blob;
+
+       if (!asn1_push_tag(data, ASN1_OID)) return false;
+
+       if (!ber_write_OID_String(&blob, OID)) {
+               data->has_error = true;
+               return false;
+       }
+
+       if (!asn1_write(data, blob.data, blob.length)) {
+               data->has_error = true;
+               return false;
+       }
+       data_blob_free(&blob);
        return asn1_pop_tag(data);
 }
 
 /* write an octet string */
-BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
+bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
 {
        asn1_push_tag(data, ASN1_OCTET_STRING);
        asn1_write(data, p, length);
@@ -224,14 +279,21 @@ BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length
 }
 
 /* write a LDAP string */
-BOOL asn1_write_LDAPString(struct asn1_data *data, const char *s)
+bool asn1_write_LDAPString(struct asn1_data *data, const char *s)
 {
        asn1_write(data, s, strlen(s));
        return !data->has_error;
 }
 
+/* write a LDAP string from a DATA_BLOB */
+bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s)
+{
+       asn1_write(data, s->data, s->length);
+       return !data->has_error;
+}
+
 /* write a general string */
-BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
+bool asn1_write_GeneralString(struct asn1_data *data, const char *s)
 {
        asn1_push_tag(data, ASN1_GENERAL_STRING);
        asn1_write_LDAPString(data, s);
@@ -239,7 +301,7 @@ BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
        return !data->has_error;
 }
 
-BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
+bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
 {
        asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
        asn1_write(data, blob->data, blob->length);
@@ -248,7 +310,7 @@ BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *bl
 }
 
 /* write a BOOLEAN */
-BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
+bool asn1_write_BOOLEAN(struct asn1_data *data, bool v)
 {
        asn1_push_tag(data, ASN1_BOOLEAN);
        asn1_write_uint8(data, v ? 0xFF : 0);
@@ -256,137 +318,140 @@ BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
        return !data->has_error;
 }
 
-BOOL asn1_read_BOOLEAN(struct asn1_data *data, BOOL *v)
+bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v)
 {
        uint8_t tmp = 0;
        asn1_start_tag(data, ASN1_BOOLEAN);
        asn1_read_uint8(data, &tmp);
        if (tmp == 0xFF) {
-               *v = True;
+               *v = true;
        } else {
-               *v = False;
+               *v = false;
        }
        asn1_end_tag(data);
        return !data->has_error;
 }
 
 /* check a BOOLEAN */
-BOOL asn1_check_BOOLEAN(struct asn1_data *data, BOOL v)
+bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
 {
        uint8_t b = 0;
 
        asn1_read_uint8(data, &b);
        if (b != ASN1_BOOLEAN) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        asn1_read_uint8(data, &b);
        if (b != v) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        return !data->has_error;
 }
 
 
 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
-BOOL asn1_load(struct asn1_data *data, DATA_BLOB blob)
+bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
 {
        ZERO_STRUCTP(data);
-       data->data = talloc_memdup(NULL, blob.data, blob.length);
+       data->data = talloc_memdup(data, blob.data, blob.length);
        if (!data->data) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        data->length = blob.length;
-       return True;
+       return true;
 }
 
 /* Peek into an ASN1 buffer, not advancing the pointer */
-BOOL asn1_peek(struct asn1_data *data, void *p, int len)
+bool asn1_peek(struct asn1_data *data, void *p, int len)
 {
+       if (data->has_error)
+               return false;
+
        if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
-               return False;
+               return false;
 
        if (data->ofs + len > data->length) {
                /* we need to mark the buffer as consumed, so the caller knows
                   this was an out of data error, and not a decode error */
                data->ofs = data->length;
-               return False;
+               return false;
        }
 
        memcpy(p, data->data + data->ofs, len);
-       return True;
+       return true;
 }
 
 /* read from a ASN1 buffer, advancing the buffer pointer */
-BOOL asn1_read(struct asn1_data *data, void *p, int len)
+bool asn1_read(struct asn1_data *data, void *p, int len)
 {
        if (!asn1_peek(data, p, len)) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
 
        data->ofs += len;
-       return True;
+       return true;
 }
 
 /* read a uint8_t from a ASN1 buffer */
-BOOL asn1_read_uint8(struct asn1_data *data, uint8_t *v)
+bool asn1_read_uint8(struct asn1_data *data, uint8_t *v)
 {
        return asn1_read(data, v, 1);
 }
 
-BOOL asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
+bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
 {
        return asn1_peek(data, v, 1);
 }
 
-BOOL asn1_peek_tag(struct asn1_data *data, uint8_t tag)
+bool asn1_peek_tag(struct asn1_data *data, uint8_t tag)
 {
        uint8_t b;
 
        if (asn1_tag_remaining(data) <= 0) {
-               return False;
+               return false;
        }
 
-       if (!asn1_peek(data, &b, sizeof(b)))
-               return False;
+       if (!asn1_peek_uint8(data, &b))
+               return false;
 
        return (b == tag);
 }
 
 /* start reading a nested asn1 structure */
-BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
+bool asn1_start_tag(struct asn1_data *data, uint8_t tag)
 {
        uint8_t b;
        struct nesting *nesting;
        
        if (!asn1_read_uint8(data, &b))
-               return False;
+               return false;
 
        if (b != tag) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
-       nesting = talloc(NULL, struct nesting);
+       nesting = talloc(data, struct nesting);
        if (!nesting) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
 
        if (!asn1_read_uint8(data, &b)) {
-               return False;
+               return false;
        }
 
        if (b & 0x80) {
                int n = b & 0x7f;
                if (!asn1_read_uint8(data, &b))
-                       return False;
+                       return false;
                nesting->taglen = b;
                while (n > 1) {
                        if (!asn1_read_uint8(data, &b)) 
-                               return False;
+                               return false;
                        nesting->taglen = (nesting->taglen << 8) | b;
                        n--;
                }
@@ -397,33 +462,32 @@ BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
        nesting->next = data->nesting;
        data->nesting = nesting;
        if (asn1_tag_remaining(data) == -1) {
-               return False;
+               return false;
        }
        return !data->has_error;
 }
 
-
 /* stop reading a tag */
-BOOL asn1_end_tag(struct asn1_data *data)
+bool asn1_end_tag(struct asn1_data *data)
 {
        struct nesting *nesting;
 
        /* make sure we read it all */
        if (asn1_tag_remaining(data) != 0) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
 
        nesting = data->nesting;
 
        if (!nesting) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
 
        data->nesting = nesting->next;
        talloc_free(nesting);
-       return True;
+       return true;
 }
 
 /* work out how many bytes are left in this nested tag */
@@ -435,74 +499,121 @@ int asn1_tag_remaining(struct asn1_data *data)
        }
 
        if (!data->nesting) {
-               data->has_error = True;
+               data->has_error = true;
                return -1;
        }
        remaining = data->nesting->taglen - (data->ofs - data->nesting->start);
        if (remaining > (data->length - data->ofs)) {
-               data->has_error = True;
+               data->has_error = true;
                return -1;
        }
        return remaining;
 }
 
-/* read an object ID from a ASN1 buffer */
-BOOL asn1_read_OID(struct asn1_data *data, const char **OID)
+/* read an object ID from a data blob */
+bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID)
 {
-       uint8_t b;
+       int i;
+       uint8_t *b;
+       uint_t v;
        char *tmp_oid = NULL;
 
-       if (!asn1_start_tag(data, ASN1_OID)) return False;
-       asn1_read_uint8(data, &b);
+       if (blob.length < 2) return false;
+
+       b = blob.data;
 
-       tmp_oid = talloc_asprintf(NULL, "%u",  b/40);
-       tmp_oid = talloc_asprintf_append(tmp_oid, " %u",  b%40);
+       tmp_oid = talloc_asprintf(mem_ctx, "%u",  b[0]/40);
+       if (!tmp_oid) goto nomem;
+       tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u",  b[0]%40);
+       if (!tmp_oid) goto nomem;
+
+       for(i = 1, v = 0; i < blob.length; i++) {
+               v = (v<<7) | (b[i]&0x7f);
+               if ( ! (b[i] & 0x80)) {
+                       tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u",  v);
+                       v = 0;
+               }
+               if (!tmp_oid) goto nomem;
+       }
 
-       while (!data->has_error && asn1_tag_remaining(data) > 0) {
-               uint_t v = 0;
-               do {
-                       asn1_read_uint8(data, &b);
-                       v = (v<<7) | (b&0x7f);
-               } while (!data->has_error && (b & 0x80));
-               tmp_oid = talloc_asprintf_append(tmp_oid, " %u",  v);
+       if (v != 0) {
+               talloc_free(tmp_oid);
+               return false;
        }
 
+       *OID = tmp_oid;
+       return true;
+
+nomem: 
+       return false;
+}
+
+/* read an object ID from a ASN1 buffer */
+bool asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, const char **OID)
+{
+       DATA_BLOB blob;
+       int len;
+
+       if (!asn1_start_tag(data, ASN1_OID)) return false;
+
+       len = asn1_tag_remaining(data);
+       if (len < 0) {
+               data->has_error = true;
+               return false;
+       }
+
+       blob = data_blob(NULL, len);
+       if (!blob.data) {
+               data->has_error = true;
+               return false;
+       }
+
+       asn1_read(data, blob.data, len);
        asn1_end_tag(data);
+       if (data->has_error) {
+               data_blob_free(&blob);
+               return false;
+       }
 
-       *OID = talloc_strdup(NULL, tmp_oid);
-       talloc_free(tmp_oid);
+       if (!ber_read_OID_String(mem_ctx, blob, OID)) {
+               data->has_error = true;
+               data_blob_free(&blob);
+               return false;
+       }
 
-       return (*OID && !data->has_error);
+       data_blob_free(&blob);
+       return true;
 }
 
 /* check that the next object ID is correct */
-BOOL asn1_check_OID(struct asn1_data *data, const char *OID)
+bool asn1_check_OID(struct asn1_data *data, const char *OID)
 {
        const char *id;
 
-       if (!asn1_read_OID(data, &id)) return False;
+       if (!asn1_read_OID(data, data, &id)) return false;
 
        if (strcmp(id, OID) != 0) {
-               data->has_error = True;
-               return False;
+               talloc_free(discard_const(id));
+               data->has_error = true;
+               return false;
        }
        talloc_free(discard_const(id));
-       return True;
+       return true;
 }
 
 /* read a LDAPString from a ASN1 buffer */
-BOOL asn1_read_LDAPString(struct asn1_data *data, char **s)
+bool asn1_read_LDAPString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
 {
        int len;
        len = asn1_tag_remaining(data);
        if (len < 0) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
-       *s = talloc_size(NULL, len+1);
+       *s = talloc_array(mem_ctx, char, len+1);
        if (! *s) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        asn1_read(data, *s, len);
        (*s)[len] = 0;
@@ -511,29 +622,29 @@ BOOL asn1_read_LDAPString(struct asn1_data *data, char **s)
 
 
 /* read a GeneralString from a ASN1 buffer */
-BOOL asn1_read_GeneralString(struct asn1_data *data, char **s)
+bool asn1_read_GeneralString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
 {
-       if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
-       if (!asn1_read_LDAPString(data, s)) return False;
+       if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return false;
+       if (!asn1_read_LDAPString(data, mem_ctx, s)) return false;
        return asn1_end_tag(data);
 }
 
 
 /* read a octet string blob */
-BOOL asn1_read_OctetString(struct asn1_data *data, DATA_BLOB *blob)
+bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
 {
        int len;
        ZERO_STRUCTP(blob);
-       if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
+       if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return false;
        len = asn1_tag_remaining(data);
        if (len < 0) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
-       *blob = data_blob(NULL, len+1);
+       *blob = data_blob_talloc(mem_ctx, NULL, len+1);
        if (!blob->data) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        asn1_read(data, blob->data, len);
        asn1_end_tag(data);
@@ -543,61 +654,61 @@ BOOL asn1_read_OctetString(struct asn1_data *data, DATA_BLOB *blob)
        if (data->has_error) {
                data_blob_free(blob);
                *blob = data_blob(NULL, 0);
-               return False;
+               return false;
        }
-       return True;
+       return true;
 }
 
-BOOL asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
+bool asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
 {
        int len;
        ZERO_STRUCTP(blob);
-       if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return False;
+       if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return false;
        len = asn1_tag_remaining(data);
        if (len < 0) {
-               data->has_error = True;
-               return False;
+               data->has_error = true;
+               return false;
        }
        *blob = data_blob(NULL, len);
-       if (!blob->data) {
-               data->has_error = True;
-               return False;
+       if ((len != 0) && (!blob->data)) {
+               data->has_error = true;
+               return false;
        }
        asn1_read(data, blob->data, len);
        asn1_end_tag(data);
        return !data->has_error;
 }
 
-/* read an interger without tag*/
-BOOL asn1_read_implicit_Integer(struct asn1_data *data, int *i)
+/* read an integer without tag*/
+bool asn1_read_implicit_Integer(struct asn1_data *data, int *i)
 {
        uint8_t b;
        *i = 0;
 
        while (!data->has_error && asn1_tag_remaining(data)>0) {
-               if (!asn1_read_uint8(data, &b)) return False;
+               if (!asn1_read_uint8(data, &b)) return false;
                *i = (*i << 8) + b;
        }
        return !data->has_error;        
        
 }
 
-/* read an interger */
-BOOL asn1_read_Integer(struct asn1_data *data, int *i)
+/* read an integer */
+bool asn1_read_Integer(struct asn1_data *data, int *i)
 {
        *i = 0;
 
-       if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
-       if (!asn1_read_implicit_Integer(data, i)) return False;
+       if (!asn1_start_tag(data, ASN1_INTEGER)) return false;
+       if (!asn1_read_implicit_Integer(data, i)) return false;
        return asn1_end_tag(data);      
 }
 
-/* read an interger */
-BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
+/* read an integer */
+bool asn1_read_enumerated(struct asn1_data *data, int *v)
 {
        *v = 0;
        
-       if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
+       if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
        while (!data->has_error && asn1_tag_remaining(data)>0) {
                uint8_t b;
                asn1_read_uint8(data, &b);
@@ -606,24 +717,24 @@ BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
        return asn1_end_tag(data);      
 }
 
-/* check a enumarted value is correct */
-BOOL asn1_check_enumerated(struct asn1_data *data, int v)
+/* check a enumerated value is correct */
+bool asn1_check_enumerated(struct asn1_data *data, int v)
 {
        uint8_t b;
-       if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
+       if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
        asn1_read_uint8(data, &b);
        asn1_end_tag(data);
 
        if (v != b)
-               data->has_error = False;
+               data->has_error = false;
 
        return !data->has_error;
 }
 
-/* write an enumarted value to the stream */
-BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
+/* write an enumerated value to the stream */
+bool asn1_write_enumerated(struct asn1_data *data, uint8_t v)
 {
-       if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
+       if (!asn1_push_tag(data, ASN1_ENUMERATED)) return false;
        asn1_write_uint8(data, v);
        asn1_pop_tag(data);
        return !data->has_error;
@@ -634,19 +745,21 @@ BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
 */
 NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
 {
-       struct asn1_data asn1;
+       struct asn1_data *asn1 = asn1_init(NULL);
        int size;
 
-       ZERO_STRUCT(asn1);
-       asn1.data = blob.data;
-       asn1.length = blob.length;
-       asn1_start_tag(&asn1, tag);
-       if (asn1.has_error) {
-               talloc_free(asn1.nesting);
+       NT_STATUS_HAVE_NO_MEMORY(asn1);
+
+       asn1->data = blob.data;
+       asn1->length = blob.length;
+       asn1_start_tag(asn1, tag);
+       if (asn1->has_error) {
+               talloc_free(asn1);
                return STATUS_MORE_ENTRIES;
        }
-       size = asn1_tag_remaining(&asn1) + asn1.ofs;
-       talloc_free(asn1.nesting);
+       size = asn1_tag_remaining(asn1) + asn1->ofs;
+
+       talloc_free(asn1);
 
        if (size > blob.length) {
                return STATUS_MORE_ENTRIES;