aboutsummaryrefslogtreecommitdiff
path: root/lib/asn1/template.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1/template.c')
-rw-r--r--lib/asn1/template.c163
1 files changed, 86 insertions, 77 deletions
diff --git a/lib/asn1/template.c b/lib/asn1/template.c
index 3e0b6932357e..fe0dc6c2f773 100644
--- a/lib/asn1/template.c
+++ b/lib/asn1/template.c
@@ -3,7 +3,7 @@
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
- * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,17 +36,7 @@
#include "der_locl.h"
#include <com_err.h>
-#if 0
-#define ABORT_ON_ERROR() abort()
-#else
-#define ABORT_ON_ERROR() do { } while(0)
-#endif
-
-#define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset))
-#define DPO(data,offset) ((void *)(((unsigned char *)data) + offset))
-
-
-static struct asn1_type_func prim[] = {
+struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = {
#define el(name, type) { \
(asn1_type_encode)der_put_##name, \
(asn1_type_decode)der_get_##name, \
@@ -66,7 +56,9 @@ static struct asn1_type_func prim[] = {
el(integer, int),
el(heim_integer, heim_integer),
el(integer, int),
+ el(integer64, int64_t),
el(unsigned, unsigned),
+ el(unsigned64, uint64_t),
el(general_string, heim_general_string),
el(octet_string, heim_octet_string),
elber(octet_string, heim_octet_string),
@@ -89,8 +81,8 @@ static struct asn1_type_func prim[] = {
#undef elber
};
-static size_t
-sizeofType(const struct asn1_template *t)
+size_t
+_asn1_sizeofType(const struct asn1_template *t)
{
return t->offset;
}
@@ -106,8 +98,8 @@ sizeofType(const struct asn1_template *t)
*/
static void
-bmember_get_bit(const unsigned char *p, void *data,
- unsigned int bit, size_t size)
+_asn1_bmember_get_bit(const unsigned char *p, void *data,
+ unsigned int bit, size_t size)
{
unsigned int localbit = bit % 8;
if ((*p >> (7 - localbit)) & 1) {
@@ -119,8 +111,8 @@ bmember_get_bit(const unsigned char *p, void *data,
}
}
-static int
-bmember_isset_bit(const void *data, unsigned int bit, size_t size)
+int
+_asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size)
{
#ifdef WORDS_BIGENDIAN
if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1)))
@@ -133,13 +125,13 @@ bmember_isset_bit(const void *data, unsigned int bit, size_t size)
#endif
}
-static void
-bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
- size_t size, unsigned int *bitset)
+void
+_asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit,
+ size_t size, unsigned int *bitset)
{
unsigned int localbit = bit % 8;
- if (bmember_isset_bit(data, bit, size)) {
+ if (_asn1_bmember_isset_bit(data, bit, size)) {
*p |= (1 << (7 - localbit));
if (*bitset == 0)
*bitset = (7 - localbit) + 1;
@@ -166,19 +158,19 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
switch (t->tt & A1_OP_MASK) {
case A1_OP_TYPE:
case A1_OP_TYPE_EXTERN: {
- size_t newsize, size;
+ size_t newsize, elsize;
void *el = DPO(data, t->offset);
void **pel = (void **)el;
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
- size = sizeofType(t->ptr);
+ elsize = _asn1_sizeofType(t->ptr);
} else {
const struct asn1_type_func *f = t->ptr;
- size = f->size;
+ elsize = f->size;
}
if (t->tt & A1_FLAG_OPTIONAL) {
- *pel = calloc(1, size);
+ *pel = calloc(1, elsize);
if (*pel == NULL)
return ENOMEM;
el = *pel;
@@ -250,7 +242,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
if (t->tt & A1_FLAG_OPTIONAL) {
void **el = (void **)data;
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
*el = calloc(1, ellen);
if (*el == NULL)
@@ -262,8 +254,13 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
if (ret)
return ret;
- if (newsize != datalen)
+ if (is_indefinite) {
+ /* If we use indefinite encoding, the newsize is the datasize. */
+ datalen = newsize;
+ } else if (newsize != datalen) {
+ /* Check for hidden data that might be after the real tag */
return ASN1_EXTRA_DATA;
+ }
len -= datalen;
p += datalen;
@@ -300,12 +297,12 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
if (flags & A1_PF_INDEFINTE)
type++;
- if (type >= sizeof(prim)/sizeof(prim[0])) {
+ if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
ABORT_ON_ERROR();
return ASN1_PARSE_ERROR;
}
- ret = (prim[type].decode)(p, len, el, &newsize);
+ ret = (asn1_template_prim[type].decode)(p, len, el, &newsize);
if (ret)
return ret;
p += newsize; len -= newsize;
@@ -316,7 +313,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
case A1_OP_SEQOF: {
struct template_of *el = DPO(data, t->offset);
size_t newsize;
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
size_t vallength = 0;
while (len > 0) {
@@ -345,19 +342,19 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
}
case A1_OP_BMEMBER: {
const struct asn1_template *bmember = t->ptr;
- size_t size = bmember->offset;
- size_t elements = A1_HEADER_LEN(bmember);
+ size_t bsize = bmember->offset;
+ size_t belements = A1_HEADER_LEN(bmember);
size_t pos = 0;
bmember++;
- memset(data, 0, size);
+ memset(data, 0, bsize);
if (len < 1)
return ASN1_OVERRUN;
p++; len--;
- while (elements && len) {
+ while (belements && len) {
while (bmember->offset / 8 > pos / 8) {
if (len < 1)
break;
@@ -365,8 +362,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
pos += 8;
}
if (len) {
- bmember_get_bit(p, data, bmember->offset, size);
- elements--; bmember++;
+ _asn1_bmember_get_bit(p, data, bmember->offset, bsize);
+ belements--; bmember++;
}
}
len = 0;
@@ -378,6 +375,9 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
size_t datalen;
unsigned int i;
+ /* provide a saner value as default, we should have a NO element value */
+ *element = 1;
+
for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) {
/* should match first tag instead, store it in choice.tt */
ret = _asn1_decode(choice[i].ptr, 0, p, len,
@@ -513,12 +513,12 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
size_t newsize;
const void *el = DPOC(data, t->offset);
- if (type > sizeof(prim)/sizeof(prim[0])) {
+ if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
ABORT_ON_ERROR();
return ASN1_PARSE_ERROR;
}
- ret = (prim[type].encode)(p, len, el, &newsize);
+ ret = (asn1_template_prim[type].encode)(p, len, el, &newsize);
if (ret)
return ret;
p -= newsize; len -= newsize;
@@ -527,8 +527,8 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
}
case A1_OP_SETOF: {
const struct template_of *el = DPOC(data, t->offset);
- size_t ellen = sizeofType(t->ptr);
- struct heim_octet_string *val;
+ size_t ellen = _asn1_sizeofType(t->ptr);
+ heim_octet_string *val;
unsigned char *elptr = el->val;
size_t i, totallen;
@@ -538,7 +538,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
if (el->len > UINT_MAX/sizeof(val[0]))
return ERANGE;
- val = malloc(sizeof(val[0]) * el->len);
+ val = calloc(el->len, sizeof(val[0]));
if (val == NULL)
return ENOMEM;
@@ -547,7 +547,13 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
size_t l;
val[i].length = _asn1_length(t->ptr, elptr);
- val[i].data = malloc(val[i].length);
+ if (val[i].length) {
+ val[i].data = malloc(val[i].length);
+ if (val[i].data == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ }
ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1),
val[i].length, elptr, &l);
@@ -565,9 +571,8 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
if (ret == 0 && totallen > len)
ret = ASN1_OVERFLOW;
if (ret) {
- do {
+ for (i = 0; i < el->len; i++)
free(val[i].data);
- } while(i-- > 0);
free(val);
return ret;
}
@@ -589,7 +594,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
}
case A1_OP_SEQOF: {
struct template_of *el = DPO(data, t->offset);
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
size_t newsize;
unsigned int i;
unsigned char *elptr = el->val;
@@ -613,21 +618,21 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
}
case A1_OP_BMEMBER: {
const struct asn1_template *bmember = t->ptr;
- size_t size = bmember->offset;
- size_t elements = A1_HEADER_LEN(bmember);
+ size_t bsize = bmember->offset;
+ size_t belements = A1_HEADER_LEN(bmember);
size_t pos;
unsigned char c = 0;
unsigned int bitset = 0;
int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
- bmember += elements;
+ bmember += belements;
if (rfc1510)
pos = 31;
else
pos = bmember->offset;
- while (elements && len) {
+ while (belements && len) {
while (bmember->offset / 8 < pos / 8) {
if (rfc1510 || bitset || c) {
if (len < 1)
@@ -637,8 +642,8 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
c = 0;
pos -= 8;
}
- bmember_put_bit(&c, data, bmember->offset, size, &bitset);
- elements--; bmember--;
+ _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset);
+ belements--; bmember--;
}
if (rfc1510 || bitset) {
if (len < 1)
@@ -747,17 +752,17 @@ _asn1_length(const struct asn1_template *t, const void *data)
unsigned int type = A1_PARSE_TYPE(t->tt);
const void *el = DPOC(data, t->offset);
- if (type > sizeof(prim)/sizeof(prim[0])) {
+ if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
ABORT_ON_ERROR();
break;
}
- ret += (prim[type].length)(el);
+ ret += (asn1_template_prim[type].length)(el);
break;
}
case A1_OP_SETOF:
case A1_OP_SEQOF: {
const struct template_of *el = DPOC(data, t->offset);
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
const unsigned char *element = el->val;
unsigned int i;
@@ -771,7 +776,7 @@ _asn1_length(const struct asn1_template *t, const void *data)
case A1_OP_BMEMBER: {
const struct asn1_template *bmember = t->ptr;
size_t size = bmember->offset;
- size_t elements = A1_HEADER_LEN(bmember);
+ size_t belements = A1_HEADER_LEN(bmember);
int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
if (rfc1510) {
@@ -780,14 +785,14 @@ _asn1_length(const struct asn1_template *t, const void *data)
ret += 1;
- bmember += elements;
+ bmember += belements;
- while (elements) {
- if (bmember_isset_bit(data, bmember->offset, size)) {
+ while (belements) {
+ if (_asn1_bmember_isset_bit(data, bmember->offset, size)) {
ret += (bmember->offset / 8) + 1;
break;
}
- elements--; bmember--;
+ belements--; bmember--;
}
}
break;
@@ -855,11 +860,11 @@ _asn1_free(const struct asn1_template *t, void *data)
unsigned int type = A1_PARSE_TYPE(t->tt);
void *el = DPO(data, t->offset);
- if (type > sizeof(prim)/sizeof(prim[0])) {
+ if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
ABORT_ON_ERROR();
break;
}
- (prim[type].release)(el);
+ (asn1_template_prim[type].release)(el);
break;
}
case A1_OP_TAG: {
@@ -882,7 +887,7 @@ _asn1_free(const struct asn1_template *t, void *data)
case A1_OP_SETOF:
case A1_OP_SEQOF: {
struct template_of *el = DPO(data, t->offset);
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
unsigned char *element = el->val;
unsigned int i;
@@ -947,7 +952,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to)
size_t size;
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
- size = sizeofType(t->ptr);
+ size = _asn1_sizeofType(t->ptr);
} else {
const struct asn1_type_func *f = t->ptr;
size = f->size;
@@ -985,11 +990,11 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to)
const void *fel = DPOC(from, t->offset);
void *tel = DPO(to, t->offset);
- if (type > sizeof(prim)/sizeof(prim[0])) {
+ if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
ABORT_ON_ERROR();
return ASN1_PARSE_ERROR;
}
- ret = (prim[type].copy)(fel, tel);
+ ret = (asn1_template_prim[type].copy)(fel, tel);
if (ret)
return ret;
break;
@@ -1012,14 +1017,14 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to)
}
from = *fel;
- to = *tel = calloc(1, sizeofType(t->ptr));
+ to = *tel = calloc(1, _asn1_sizeofType(t->ptr));
if (to == NULL)
return ENOMEM;
}
ret = _asn1_copy(t->ptr, from, to);
if (ret) {
- if (t->tt & A1_FLAG_OPTIONAL) {
+ if (tel) {
free(*tel);
*tel = NULL;
}
@@ -1035,7 +1040,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to)
case A1_OP_SEQOF: {
const struct template_of *fel = DPOC(from, t->offset);
struct template_of *tel = DPO(to, t->offset);
- size_t ellen = sizeofType(t->ptr);
+ size_t ellen = _asn1_sizeofType(t->ptr);
unsigned int i;
tel->val = calloc(fel->len, ellen);
@@ -1097,10 +1102,8 @@ _asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned c
int ret;
memset(data, 0, t->offset);
ret = _asn1_decode(t, flags, p, len, data, size);
- if (ret) {
- _asn1_free(t, data);
- memset(data, 0, t->offset);
- }
+ if (ret)
+ _asn1_free_top(t, data);
return ret;
}
@@ -1111,9 +1114,15 @@ _asn1_copy_top(const struct asn1_template *t, const void *from, void *to)
int ret;
memset(to, 0, t->offset);
ret = _asn1_copy(t, from, to);
- if (ret) {
- _asn1_free(t, to);
- memset(to, 0, t->offset);
- }
+ if (ret)
+ _asn1_free_top(t, to);
+
return ret;
}
+
+void
+_asn1_free_top(const struct asn1_template *t, void *data)
+{
+ _asn1_free(t, data);
+ memset(data, 0, t->offset);
+}