summaryrefslogtreecommitdiff
path: root/source3/libsmb/asn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/asn1.c')
-rw-r--r--source3/libsmb/asn1.c186
1 files changed, 168 insertions, 18 deletions
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c
index e4c2d3af80..17b1ee1089 100644
--- a/source3/libsmb/asn1.c
+++ b/source3/libsmb/asn1.c
@@ -30,9 +30,13 @@ void asn1_free(ASN1_DATA *data)
/* write to the ASN1 buffer, advancing the buffer pointer */
BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
{
+ if (data->has_error) return False;
if (data->length < data->ofs+len) {
data->data = Realloc(data->data, data->ofs+len);
- if (!data->data) return False;
+ if (!data->data) {
+ data->has_error = True;
+ return False;
+ }
data->length = data->ofs+len;
}
memcpy(data->data + data->ofs, p, len);
@@ -53,13 +57,15 @@ BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
asn1_write_uint8(data, tag);
nesting = (struct nesting *)malloc(sizeof(struct nesting));
- if (!nesting) return False;
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
nesting->start = data->ofs;
nesting->next = data->nesting;
data->nesting = nesting;
- asn1_write_uint8(data, 0xff);
- return True;
+ return asn1_write_uint8(data, 0xff);
}
/* pop a tag */
@@ -71,6 +77,7 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
nesting = data->nesting;
if (!nesting) {
+ data->has_error = True;
return False;
}
len = data->ofs - (nesting->start+1);
@@ -79,8 +86,8 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
need to correct our mistake */
if (len > 127) {
data->data[nesting->start] = 0x82;
- asn1_write_uint8(data, 0);
- asn1_write_uint8(data, 0);
+ 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;
@@ -99,10 +106,10 @@ BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
unsigned v, v2;
char *p = (char *)OID;
- asn1_push_tag(data, ASN1_OID);
+ if (!asn1_push_tag(data, ASN1_OID)) return False;
v = strtol(p, &p, 10);
v2 = strtol(p, &p, 10);
- asn1_write_uint8(data, 40*v + v2);
+ if (!asn1_write_uint8(data, 40*v + v2)) return False;
while (*p) {
v = strtol(p, &p, 10);
@@ -110,10 +117,9 @@ BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
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));
- asn1_write_uint8(data, v&0x7f);
+ if (!asn1_write_uint8(data, v&0x7f)) return False;
}
- asn1_pop_tag(data);
- return True;
+ return asn1_pop_tag(data);
}
/* write an octet string */
@@ -122,7 +128,7 @@ BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
asn1_push_tag(data, ASN1_OCTET_STRING);
asn1_write(data, p, length);
asn1_pop_tag(data);
- return True;
+ return !data->has_error;
}
/* write a general string */
@@ -131,7 +137,7 @@ BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
asn1_push_tag(data, ASN1_GENERAL_STRING);
asn1_write(data, s, strlen(s));
asn1_pop_tag(data);
- return True;
+ return !data->has_error;
}
/* write a BOOLEAN */
@@ -139,17 +145,20 @@ BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
{
asn1_write_uint8(data, ASN1_BOOLEAN);
asn1_write_uint8(data, v);
- return True;
+ return !data->has_error;
}
/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
-BOOL asn1_load(ASN1_DATA *data, void *p, size_t length)
+BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
{
ZERO_STRUCTP(data);
- data->data = memdup(p, length);
- if (!data->data) return False;
- data->length = length;
+ data->data = memdup(blob.data, blob.length);
+ if (!data->data) {
+ data->has_error = True;
+ return False;
+ }
+ data->length = blob.length;
return True;
}
@@ -157,6 +166,7 @@ BOOL asn1_load(ASN1_DATA *data, void *p, size_t length)
BOOL asn1_read(ASN1_DATA *data, void *p, int len)
{
if (data->ofs + len > data->length) {
+ data->has_error = True;
return False;
}
memcpy(p, data->data + data->ofs, len);
@@ -164,4 +174,144 @@ BOOL asn1_read(ASN1_DATA *data, void *p, int len)
return True;
}
+/* read a uint8 from a ASN1 buffer */
+BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
+{
+ return asn1_read(data, v, 1);
+}
+/* start reading a nested asn1 structure */
+BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
+{
+ uint8 b;
+ struct nesting *nesting;
+
+ asn1_read_uint8(data, &b);
+ if (b != tag) {
+ data->has_error = True;
+ return False;
+ }
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ asn1_read_uint8(data, &b);
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (n != 2) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read_uint8(data, &b);
+ nesting->taglen = b<<8;
+ asn1_read_uint8(data, &b);
+ nesting->taglen |= b;
+ } else {
+ nesting->taglen = b;
+ }
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return !data->has_error;
+}
+
+
+/* stop reading a tag */
+BOOL asn1_end_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+
+ /* make sure we read it all */
+ if (asn1_tag_remaining(data) != 0) {
+ data->has_error = True;
+ return False;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return True;
+}
+
+/* work out how many bytes are left in this nested tag */
+int asn1_tag_remaining(ASN1_DATA *data)
+{
+ if (!data->nesting) {
+ data->has_error = True;
+ return -1;
+ }
+ return data->nesting->taglen - (data->ofs - data->nesting->start);
+}
+
+/* read an object ID from a ASN1 buffer */
+BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
+{
+ uint8 b;
+ pstring oid;
+ fstring el;
+
+ if (!asn1_start_tag(data, ASN1_OID)) return False;
+ asn1_read_uint8(data, &b);
+
+ oid[0] = 0;
+ snprintf(el, sizeof(el), "%u", b/40);
+ pstrcat(oid, el);
+ snprintf(el, sizeof(el), " %u", b%40);
+ pstrcat(oid, el);
+
+ while (asn1_tag_remaining(data) > 0) {
+ unsigned v = 0;
+ do {
+ asn1_read_uint8(data, &b);
+ v = (v<<7) | (b&0x7f);
+ } while (!data->has_error && b & 0x80);
+ snprintf(el, sizeof(el), " %u", v);
+ pstrcat(oid, el);
+ }
+
+ asn1_end_tag(data);
+
+ *OID = strdup(oid);
+
+ return !data->has_error;
+}
+
+/* check that the next object ID is correct */
+BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
+{
+ char *id;
+
+ if (!asn1_read_OID(data, &id)) return False;
+
+ if (strcmp(id, OID) != 0) {
+ data->has_error = True;
+ return False;
+ }
+ free(id);
+ return True;
+}
+
+/* read a GeneralString from a ASN1 buffer */
+BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
+{
+ int len;
+ if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
+ len = asn1_tag_remaining(data);
+ *s = malloc(len+1);
+ if (! *s) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read(data, *s, len);
+ (*s)[len] = 0;
+ asn1_end_tag(data);
+ return !data->has_error;
+}