/* From libtasn1's libtasn.h */
-#define ASN1_CLASS_UNIVERSAL 0x00
-#define ASN1_CLASS_APPLICATION 0x40
-#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80
-#define ASN1_CLASS_PRIVATE 0xC0
-#define ASN1_CLASS_STRUCTURED 0x20
-
-#define ASN1_TAG_BOOLEAN 0x01
-#define ASN1_TAG_INTEGER 0x02
-#define ASN1_TAG_SEQUENCE 0x10
-#define ASN1_TAG_SET 0x11
-#define ASN1_TAG_OCTET_STRING 0x04
-#define ASN1_TAG_BIT_STRING 0x03
-#define ASN1_TAG_UTCTime 0x17
-#define ASN1_TAG_GENERALIZEDTime 0x18
-#define ASN1_TAG_OBJECT_ID 0x06
-#define ASN1_TAG_ENUMERATED 0x0A
-#define ASN1_TAG_NULL 0x05
-#define ASN1_TAG_GENERALSTRING 0x1B
+enum {
+ ASN1_CLASS_UNIVERSAL = 0x00,
+ ASN1_CLASS_APPLICATION = 0x40,
+ ASN1_CLASS_CONTEXT_SPECIFIC = 0x80,
+ ASN1_CLASS_PRIVATE = 0xC0,
+ ASN1_CLASS_STRUCTURED = 0x20,
+};
+enum {
+ ASN1_TAG_BOOLEAN = 0x01,
+ ASN1_TAG_INTEGER = 0x02,
+ ASN1_TAG_SEQUENCE = 0x10,
+ ASN1_TAG_SET = 0x11,
+ ASN1_TAG_OCTET_STRING = 0x04,
+ ASN1_TAG_BIT_STRING = 0x03,
+ ASN1_TAG_UTC_TIME = 0x17,
+ ASN1_TAG_GENERALIZED_TIME = 0x18,
+ ASN1_TAG_OBJECT_ID = 0x06,
+ ASN1_TAG_ENUMERATED = 0x0A,
+ ASN1_TAG_NULL = 0x05,
+ ASN1_TAG_GENERALSTRING = 0x1B,
+};
/* From libtasn1's int.h */
FLAG_RIGHT = (1<<30),
};
-typedef gboolean (*Aencoder) (gpointer data,
- GNode *node,
- guchar *buf,
- gsize n_buf);
-
-typedef struct _Aenc Aenc;
typedef struct _Atlv Atlv;
typedef struct _Anode Anode;
-typedef struct _Abuf Abuf;
-typedef struct _Abits Abits;
-
-struct _Aenc {
- Aencoder encoder;
- gpointer data;
- GDestroyNotify destroy;
-};
struct _Atlv {
guchar cls;
gulong tag;
gint off;
- gint oft;
gint len;
- const guchar *buf;
- const guchar *end;
+
+ /* An actual value here */
+ GBytes *value;
+
+ /* Reference to what was decoded */
+ GBytes *decoded;
+
+ /* Chain this into a tree */
+ struct _Atlv *child;
+ struct _Atlv *next;
+
+ /* Used during encoding */
+ guint bits_empty : 3;
+ guint prefix_for_bit_string : 1;
+ guint prefix_with_zero_byte : 1;
+ guint sorted : 1;
};
struct _Anode {
const EggAsn1xDef *join;
GList *opts;
- Atlv *tlv;
- Aenc *enc;
+ GBytes *value;
+ Atlv *parsed;
- GBytes *backing;
gchar* failure;
- gint chosen : 1;
-};
-
-struct _Abuf {
- guchar* data;
- gsize n_data;
- gpointer user_data;
-};
-
-struct _Abits {
- guint n_bits;
- GBytes *bits;
+ guint chosen : 1;
+ guint bits_empty : 3;
+ guint guarantee_unsigned : 1;
};
/* Forward Declarations */
-static gboolean anode_decode_anything (GNode*, GBytes*, Atlv*);
-static gboolean anode_decode_anything_for_flags (GNode *, GBytes*, Atlv*, gint);
-static gboolean anode_validate_anything (GNode*, gboolean);
-static gboolean anode_encode_prepare (GNode*, gboolean want);
+static gboolean anode_decode_anything (GNode *, Atlv *);
+static gboolean anode_decode_one (GNode *, Atlv *);
+static GBytes * anode_default_boolean (GNode *node);
+static GBytes * anode_default_integer (GNode *node);
+static gboolean anode_validate_anything (GNode *, gboolean);
+static Atlv * anode_build_anything (GNode*, gboolean want);
static gint
atoin (const char *p, gint digits)
return ret;
}
+static const guchar *
+bytes_get_end (GBytes *data)
+{
+ const guchar *beg;
+ gsize size;
+ beg = g_bytes_get_data (data, &size);
+ return beg + size;
+}
+
+typedef struct {
+ EggAllocator allocator;
+ gpointer allocated;
+} AllocatorClosure;
+
+static void
+allocator_closure_free (gpointer data)
+{
+ AllocatorClosure *closure = data;
+ g_assert (closure->allocator);
+ (closure->allocator) (closure->allocated, 0);
+ g_slice_free (AllocatorClosure, closure);
+}
+
+static GBytes *
+bytes_new_with_allocator (EggAllocator allocator,
+ guchar **data,
+ gsize length)
+{
+ AllocatorClosure *closure;
+
+ if (allocator == g_realloc)
+ allocator = NULL;
+
+ if (allocator) {
+ *data = (allocator) (NULL, length + 1);
+ if (allocator == NULL)
+ return NULL;
+ closure = g_slice_new (AllocatorClosure);
+ closure->allocated = *data;
+ closure->allocator = allocator;
+ return g_bytes_new_with_free_func (*data, length,
+ allocator_closure_free,
+ closure);
+ } else {
+ *data = g_malloc (length);
+ return g_bytes_new_take (*data, length);
+ }
+}
+
static GNode*
anode_new (const EggAsn1xDef *def)
{
return g_list_reverse (res);
}
-static gint
-compare_tlvs (Atlv *tlva, Atlv *tlvb)
+static Atlv *
+atlv_new (void)
{
- gint la = tlva->off + tlva->len;
- gint lb = tlvb->off + tlvb->len;
- gint res;
-
- g_assert (tlva->buf);
- g_assert (tlvb->buf);
- res = memcmp (tlva->buf, tlvb->buf, MIN (la, lb));
- if (la == lb || res != 0)
- return res;
- return la < lb ? -1 : 1;
+ return g_slice_new0 (Atlv);
}
-static inline GBytes *
-anode_get_backing (GNode *node)
+static void
+atlv_free (Atlv *tlv)
{
- Anode *an = node->data;
- return an->backing;
-}
+ if (!tlv)
+ return;
-static inline void
-anode_clr_backing (GNode *node)
-{
- Anode *an = node->data;
- if (an->backing)
- g_bytes_unref (an->backing);
- an->backing = NULL;
-}
+ /* Free attached TLVs */
+ atlv_free (tlv->child);
+ atlv_free (tlv->next);
-static inline void
-anode_set_backing (GNode *node,
- GBytes *backing)
-{
- Anode *an = node->data;
- if (backing)
- g_bytes_ref (backing);
- if (an->backing)
- g_bytes_unref (an->backing);
- an->backing = backing;
+ /* Free the TLV */
+ if (tlv->decoded)
+ g_bytes_unref (tlv->decoded);
+ if (tlv->value)
+ g_bytes_unref (tlv->value);
+
+ g_slice_free (Atlv, tlv);
}
-static void
-anode_set_tlv_data (GNode *node,
- GBytes *backing,
- Atlv *tlv)
+static Atlv *
+atlv_dup (Atlv *tlv,
+ gboolean siblings)
{
- Anode *an = node->data;
- g_assert (an->tlv == NULL);
- g_assert (tlv->len >= 0);
- anode_set_backing (node, backing);
- an->tlv = g_slice_new0 (Atlv);
- memcpy (an->tlv, tlv, sizeof (Atlv));
+ Atlv *copy;
+
+ if (!tlv)
+ return NULL;
+
+ copy = g_slice_new0 (Atlv);
+ memcpy (copy, tlv, sizeof (Atlv));
+
+ if (tlv->value != NULL)
+ copy->value = g_bytes_ref (tlv->value);
+ if (tlv->decoded != NULL)
+ copy->decoded = g_bytes_ref (tlv->decoded);
+
+ copy->child = atlv_dup (tlv->child, TRUE);
+ if (siblings)
+ copy->next = atlv_dup (tlv->next, TRUE);
+ else
+ copy->next = NULL;
+
+ return copy;
}
-static inline Atlv *
-anode_get_tlv_data (GNode *node)
+static inline GBytes *
+anode_get_value (GNode *node)
{
Anode *an = node->data;
- return an->tlv;
+ return an->value;
}
-static void
-anode_clr_tlv_data (GNode *node)
+static inline void
+anode_clr_value (GNode *node)
{
Anode *an = node->data;
- if (an->tlv);
- g_slice_free (Atlv, an->tlv);
- an->tlv = NULL;
+ if (an->value)
+ g_bytes_unref (an->value);
+ an->value = NULL;
+
+ atlv_free (an->parsed);
+ an->parsed = NULL;
}
-static void
-anode_clr_enc_data (GNode *node)
+static inline void
+anode_take_value (GNode *node,
+ GBytes *value)
{
Anode *an = node->data;
- if (an->enc) {
- if (an->enc->destroy)
- (an->enc->destroy) (an->enc->data);
- g_slice_free (Aenc, an->enc);
- an->enc = NULL;
- }
+ anode_clr_value (node);
+ an->value = value;
}
-static void
-anode_set_enc_data (GNode *node,
- Aencoder encoder,
- gpointer data,
- GDestroyNotify destroy)
+static inline void
+anode_set_value (GNode *node,
+ GBytes *value)
{
- Anode *an = node->data;
- g_assert (!an->enc);
- an->enc = g_slice_new0 (Aenc);
- an->enc->encoder = encoder;
- an->enc->data = data;
- an->enc->destroy = destroy;
- anode_clr_backing (node);
+ anode_take_value (node, g_bytes_ref (value));
}
-static Aenc*
-anode_get_enc_data (GNode *node)
+static inline Atlv *
+anode_get_parsed (GNode *node)
{
Anode *an = node->data;
- return an->enc;
+ return an->parsed;
}
static gboolean
anode_clear (GNode *node)
{
Anode *an = node->data;
- anode_clr_backing (node);
- anode_clr_tlv_data (node);
- anode_clr_enc_data (node);
+ anode_clr_value (node);
g_free (an->failure);
an->failure = NULL;
}
}
static void
-abits_destroy (gpointer data)
-{
- Abits *ab = data;
- g_assert (ab != NULL);
- if (ab->bits)
- g_bytes_unref (ab->bits);
- g_slice_free (Abits, ab);
-}
-
-static void
anode_destroy (GNode *node)
{
if (!G_NODE_IS_ROOT (node))
return ASN1_TAG_GENERALSTRING;
case EGG_ASN1X_TIME:
if (flags & FLAG_GENERALIZED)
- return ASN1_TAG_GENERALIZEDTime;
+ return ASN1_TAG_GENERALIZED_TIME;
else if (flags & FLAG_UTC)
- return ASN1_TAG_UTCTime;
+ return ASN1_TAG_UTC_TIME;
else
g_return_val_if_reached (G_MAXULONG);
case EGG_ASN1X_SEQUENCE:
return TRUE;
}
-static gboolean
-anode_calc_explicit (GNode *node,
- guchar *cls_type)
-{
- return anode_calc_explicit_for_flags (node, anode_def_flags (node), cls_type);
-}
-
/* -------------------------------------------------------------------------
- * DECODE
+ * PARSING
*/
static gboolean
-anode_decode_cls_tag (const guchar *data, const guchar *end,
- guchar *cls, gulong *tag, gint *cb)
+atlv_parse_cls_tag (const guchar *at,
+ const guchar *end,
+ guchar *cls,
+ gulong *tag,
+ gint *off)
{
gint punt, ris, last;
gint n_data;
- g_assert (end >= data);
- g_assert (cls);
- g_assert (cb);
+ g_assert (end >= at);
+ g_assert (cls != NULL);
+ g_assert (off != NULL);
- n_data = end - data;
+ n_data = end - at;
if (n_data < 2)
return FALSE;
- *cls = data[0] & 0xE0;
+ *cls = at[0] & 0xE0;
/* short form */
- if ((data[0] & 0x1F) != 0x1F) {
- *cb = 1;
- ris = data[0] & 0x1F;
+ if ((at[0] & 0x1F) != 0x1F) {
+ *off = 1;
+ ris = at[0] & 0x1F;
/* Long form */
} else {
punt = 1;
ris = 0;
- while (punt <= n_data && data[punt] & 128) {
+ while (punt <= n_data && at[punt] & 128) {
int last = ris;
- ris = ris * 128 + (data[punt++] & 0x7F);
+ ris = ris * 128 + (at[punt++] & 0x7F);
/* wrapper around, and no bignums... */
if (ris < last)
return FALSE;
last = ris;
- ris = ris * 128 + (data[punt++] & 0x7F);
+ ris = ris * 128 + (at[punt++] & 0x7F);
/* wrapper around, and no bignums... */
if (ris < last)
return FALSE;
- *cb = punt;
+ *off = punt;
}
if (tag)
}
static gint
-anode_decode_length (const guchar *data, const guchar *end, gint *cb)
+atlv_parse_length (const guchar *at,
+ const guchar *end,
+ gint *off)
{
gint ans, last;
gint k, punt;
gint n_data;
- g_assert (data);
- g_assert (end);
- g_assert (end >= data);
- g_assert (cb);
+ g_assert (at != NULL);
+ g_assert (end != NULL);
+ g_assert (end >= at);
+ g_assert (off != NULL);
- *cb = 0;
- n_data = end - data;
+ *off = 0;
+ n_data = end - at;
if (n_data == 0)
return 0;
/* short form */
- if (!(data[0] & 128)) {
- *cb = 1;
- return data[0];
+ if (!(at[0] & 128)) {
+ *off = 1;
+ return at[0];
/* Long form */
} else {
- k = data[0] & 0x7F;
+ k = at[0] & 0x7F;
punt = 1;
/* definite length method */
ans = 0;
while (punt <= k && punt < n_data) {
last = ans;
- ans = ans * 256 + data[punt++];
+ ans = ans * 256 + at[punt++];
/* we wrapped around, no bignum support... */
if (ans < last)
ans = -1;
}
- *cb = punt;
+ *off = punt;
return ans;
}
}
static gboolean
-anode_decode_cls_tag_len (const guchar *data, const guchar *end,
- guchar *cls, gulong *tag, gint *off, gint *len)
+atlv_parse_cls_tag_len (const guchar *at,
+ const guchar *end,
+ guchar *cls,
+ gulong *tag,
+ gint *off,
+ gint *len)
{
gint cb1, cb2;
- g_assert (data);
- g_assert (end);
- g_assert (end >= data);
- g_assert (off);
- g_assert (len);
+ g_assert (at != NULL);
+ g_assert (end != NULL);
+ g_assert (end >= at);
+ g_assert (off != NULL);
+ g_assert (len != NULL);
- if (!anode_decode_cls_tag (data, end, cls, tag, &cb1))
+ if (!atlv_parse_cls_tag (at, end, cls, tag, &cb1))
return FALSE;
- *len = anode_decode_length (data + cb1, end, &cb2);
+ *len = atlv_parse_length (at + cb1, end, &cb2);
if (*len < -1)
return FALSE;
*off = cb1 + cb2;
- if (*len >= 0 && data + *off + *len > end)
+ if (*len >= 0 && at + *off + *len > end)
return FALSE;
return TRUE;
}
-static gboolean
-anode_check_indefinite_end (guchar cls, gulong tag, gint len)
-{
- return (cls == ASN1_CLASS_UNIVERSAL && tag == 0 && len == 0);
-}
-
-static gboolean
-anode_decode_indefinite_len (const guchar *data, const guchar *end, gint *rlen)
+static const gchar *
+atlv_parse_der_tag (guchar cls,
+ gulong tag,
+ gint off,
+ gint len,
+ GBytes *data,
+ const guchar **at,
+ Atlv *tlv)
{
- gint result = 0;
- gint der_len;
- gint len;
- guchar cls;
- gulong tag;
- gint off;
-
- g_assert (data <= end);
- der_len = end - data;
-
- while (result < der_len) {
- if (!anode_decode_cls_tag_len (data + result, end, &cls, &tag, &off, &len))
- return FALSE;
-
- /* The indefinite end */
- if (anode_check_indefinite_end (cls, tag, len))
- break;
-
- result += off;
+ const guchar *end;
+ const gchar *ret;
+ const guchar *beg;
+ guchar ccls;
+ gulong ctag;
+ gint clen;
+ gint coff;
+ Atlv *child;
+ Atlv *last;
+
+ g_assert (at != NULL);
+ g_assert (tlv != NULL);
+
+ end = bytes_get_end (data);
+ g_assert (*at <= end);
+
+ if (*at + off + len > end)
+ return "invalid length of tlv";
+ if (len < 0 && !(cls & ASN1_CLASS_STRUCTURED))
+ return "indefinite length on non-structured type";
+
+ beg = *at;
+
+ tlv->cls = cls;
+ tlv->tag = tag;
+ tlv->off = off;
+ tlv->len = len;
+ (*at) += off;
+
+ /* Structured TLV, with further TLVs inside */
+ if (cls & ASN1_CLASS_STRUCTURED) {
+ /* If not indefinite length, then calculate end up front */
+ if (len >= 0)
+ end = (*at) + len;
+ last = NULL;
+ while (*at < end) {
+ if (!atlv_parse_cls_tag_len (*at, end, &ccls, &ctag, &coff, &clen))
+ return "content is not encoded properly";
+
+ /* End if indefinite length? */
+ if (len < 0 && ccls == ASN1_CLASS_UNIVERSAL && ctag == 0 && clen == 0) {
+ (*at) += coff;
+ break;
+ }
- /* Mid way check */
- if (result > der_len)
- break;
+ /* Parse the child */
+ child = atlv_new ();
+ ret = atlv_parse_der_tag (ccls, ctag, coff, clen, data, at, child);
+ if (ret != NULL) {
+ atlv_free (child);
+ return ret;
+ }
- if (len < 0) {
- if (!anode_decode_indefinite_len (data + result, end, &len))
- return FALSE;
- g_assert (len >= 0);
+ /* Add the child to the right place */
+ if (last == NULL)
+ tlv->child = child;
+ else
+ last->next = child;
+ last = child;
}
- if (result + len > der_len)
- return FALSE;
- result += len;
+ /* Non-structured TLV, just a value */
+ } else {
+ tlv->value = g_bytes_new_with_free_func (*at, len,
+ (GDestroyNotify)g_bytes_unref,
+ g_bytes_ref (data));
+ (*at) += len;
}
- if (result > der_len)
- return FALSE;
- *rlen = result;
- return TRUE;
-}
+ /* Note the actual DER that we decoded */
+ tlv->decoded = g_bytes_new_with_free_func (beg, *at - beg,
+ (GDestroyNotify)g_bytes_unref,
+ g_bytes_ref (data));
-static gboolean
-anode_decode_tlv_for_data (const guchar *data, const guchar *end, Atlv *tlv)
-{
- g_assert (data <= end);
- if (!anode_decode_cls_tag_len (data, end, &tlv->cls,
- &tlv->tag, &tlv->off, &tlv->len))
- return FALSE;
- tlv->buf = data;
- if (tlv->len < 0)
- tlv->end = end;
- else
- tlv->end = tlv->buf + tlv->len + tlv->off;
- g_assert (tlv->end <= end);
- return TRUE;
+ return NULL; /* Success */
}
-static gboolean
-anode_decode_tlv_for_contents (Atlv *outer, gboolean first, Atlv *tlv)
+static const gchar *
+atlv_parse_der (GBytes *data,
+ Atlv *tlv)
{
- const guchar *data;
const guchar *end;
+ const guchar *at;
+ const gchar *ret;
+ guchar cls;
+ gulong tag;
+ gint off;
+ gint len;
+ gsize size;
- if (first) {
- data = outer->buf + outer->off;
- end = outer->end;
- } else {
- data = tlv->end;
- end = outer->end;
- }
+ at = g_bytes_get_data (data, &size);
+ g_return_val_if_fail (at != NULL, FALSE);
+ end = at + size;
- /* The end */
- if (end == data) {
- tlv->cls = ASN1_CLASS_UNIVERSAL;
- tlv->tag = 0;
- tlv->len = 0;
- tlv->off = 0;
- tlv->buf = data;
- tlv->end = end;
- return TRUE;
- }
+ if (!atlv_parse_cls_tag_len (at, end, &cls, &tag, &off, &len))
+ return "content is not encoded properly";
- g_return_val_if_fail (end > data, FALSE);
- if (!anode_decode_tlv_for_data (data, end, tlv))
- return FALSE;
+ ret = atlv_parse_der_tag (cls, tag, off, len, data, &at, tlv);
+ if (ret != NULL)
+ return ret;
- /* Caller should stop before indefinite end, and not consume */
- if (anode_check_indefinite_end (tlv->cls, tlv->tag, tlv->len)) {
- tlv->buf = data;
- tlv->end = data;
- tlv->off = 0;
- }
+ if (at != end)
+ return "extra unexpected trailing data";
- return TRUE;
+ return NULL; /* Success */
}
+/* -------------------------------------------------------------------------
+ * DECODING
+ */
+
static gboolean
anode_decode_choice (GNode *node,
- GBytes *backing,
Atlv *tlv)
{
gboolean have = FALSE;
for (child = node->children; child; child = child->next) {
an = (Anode*)child->data;
- if (!have && anode_decode_anything (child, backing, tlv)) {
+ if (anode_decode_one (child, tlv)) {
an->chosen = 1;
have = TRUE;
} else {
}
static gboolean
-anode_decode_struct_string (GNode *node, Atlv *outer)
-{
- gint i = 0;
- Atlv tlv;
-
- /* Recalculated below */
- outer->len = 0;
-
- for (i = 0; TRUE; ++i) {
- if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
- return anode_failure (node, "invalid encoding of child");
- if (tlv.tag != outer->tag)
- return anode_failure (node, "contents have an invalid tag");
- outer->len = (tlv.end - outer->buf) - outer->off;
- }
-
- g_assert (outer->len >= 0);
- return TRUE;
-}
-
-static gboolean
-anode_decode_struct_any (GNode *node, Atlv *tlv)
-{
- if (tlv->len < 0) {
- if (!anode_decode_indefinite_len (tlv->buf + tlv->off, tlv->end, &tlv->len))
- return anode_failure (node, "could not find end of encoding");
- tlv->end = tlv->buf + tlv->off + tlv->len;
- }
-
- return TRUE;
-}
-
-static gboolean
anode_decode_sequence_or_set (GNode *node,
- GBytes *backing,
- Atlv *outer)
+ Atlv *tlv)
{
- GNode *child;
- Atlv tlv;
+ Atlv *ctlv;
+ gulong tag;
gint i;
- /* Recalculated below */
- outer->len = 0;
-
/*
* The reason we can parse a set just like a sequence, is because in DER,
* the order of the SET is predefined by the tags. In addition the definitions
* we have are sorted.
*/
- for (child = node->children, i = 0; child; child = child->next, ++i) {
-
- if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
- return anode_failure (node, "invalid encoding of child");
-
- if (!anode_decode_anything (child, backing, &tlv))
- return FALSE;
-
- outer->len = (tlv.end - outer->buf) - outer->off;
+ /* Tags must be in ascending order */
+ if (anode_def_type (node) == EGG_ASN1X_SET) {
+ for (ctlv = tlv->child, i = 0; ctlv != NULL; ctlv = ctlv->next, i++) {
+ if (i > 0 && tag > ctlv->tag)
+ return anode_failure (node, "content must be in ascending order");
+ tag = ctlv->tag;
+ }
}
- g_assert (outer->len >= 0);
- return TRUE;
+ return anode_decode_anything (node->children, tlv->child);
}
static gboolean
anode_decode_sequence_or_set_of (GNode *node,
- GBytes *backing,
- Atlv *outer)
+ Atlv *tlv)
{
+ Atlv *ctlv;
GNode *child, *other;
- Atlv tlv;
+ gulong tag;
gint i;
- outer->len = 0;
-
/* The first child */
child = node->children;
g_return_val_if_fail (child, FALSE);
while (child->next)
anode_destroy (child->next);
- /* Try to dig out as many of them as possible */
- for (i = 0; TRUE; ++i) {
+ for (ctlv = tlv->child, i = 0; ctlv != NULL; ctlv = ctlv->next, i++) {
- if (!anode_decode_tlv_for_contents (outer, i == 0, &tlv))
- return anode_failure (node, "invalid encoding of child");
+ /* Tag must have same tag as top */
+ if (i == 0)
+ tag = anode_calc_tag (child);
+ else if (tag != G_MAXULONG && ctlv->tag != tag)
+ return anode_failure (node, "invalid mismatched content");
- /* The end of the road for us */
- if (tlv.off == 0)
- break;
+ /* TODO: Set of must be in ascending order in DER encoding */
if (i == 0) {
other = child;
g_node_append (node, other);
}
- if (!anode_decode_anything (other, backing, &tlv))
+ if (!anode_decode_one (other, ctlv))
return FALSE;
-
- outer->len = (tlv.end - outer->buf) - outer->off;
}
- g_assert (outer->len >= 0);
+ return TRUE;
+}
+
+static gboolean
+anode_decode_bit_string (GNode *node,
+ Atlv *tlv)
+{
+ Anode *an = node->data;
+ guchar empty, mask;
+ GBytes *value;
+ const guchar *buf;
+ gsize len;
+
+ buf = g_bytes_get_data (tlv->value, &len);
+ if (len == 0)
+ return anode_failure (node, "invalid length bit string");
+
+ /* The first byte is the number of empty bits */
+ empty = buf[0];
+ if (empty >= 8)
+ return anode_failure (node, "invalid number of empty bits");
+
+ /* Free bits at end must be zero */
+ mask = 0xFF >> (8 - empty);
+ if (len > 1 && buf[len - 1] & mask)
+ return anode_failure (node, "bit string has invalid trailing bits");
+
+ value = g_bytes_new_from_bytes (tlv->value, 1, len - 1);
+ anode_take_value (node, value);
+ an = node->data;
+ an->bits_empty = empty;
return TRUE;
}
static gboolean
anode_decode_primitive (GNode *node,
- GBytes *backing,
Atlv *tlv,
gint flags)
{
- gint type;
+ /* Must not have any tlv children */
+ g_assert (tlv->child == NULL);
- /* Must have a definite length */
- if (tlv->len < 0)
- return anode_failure (node, "primitive value with an indefinite length");
+ switch (anode_def_type (node)) {
- type = anode_def_type (node);
- switch (type) {
+ /* Handle bit strings specially */
+ case EGG_ASN1X_BIT_STRING:
+ return anode_decode_bit_string (node, tlv);
/* The primitive value types */
case EGG_ASN1X_INTEGER:
case EGG_ASN1X_ENUMERATED:
case EGG_ASN1X_BOOLEAN:
- case EGG_ASN1X_BIT_STRING:
case EGG_ASN1X_OCTET_STRING:
case EGG_ASN1X_OBJECT_ID:
case EGG_ASN1X_NULL:
case EGG_ASN1X_GENERALSTRING:
case EGG_ASN1X_TIME:
- anode_set_tlv_data (node, backing, tlv);
+ anode_set_value (node, tlv->value);
return TRUE;
- /* Transparent types */
+ /* Just use the 'parsed' which is automatically set */
case EGG_ASN1X_ANY:
- anode_set_tlv_data (node, backing, tlv);
return TRUE;
case EGG_ASN1X_CHOICE:
- if (!anode_decode_choice (node, backing, tlv))
- return FALSE;
- anode_set_tlv_data (node, backing, tlv);
- return TRUE;
+ return anode_decode_choice (node, tlv);
default:
return anode_failure (node, "primitive value of an unexpected type");
}
-
- g_assert_not_reached ();
}
static gboolean
anode_decode_structured (GNode *node,
- GBytes *backing,
Atlv *tlv,
gint flags)
{
- gboolean definite;
- const guchar *end;
- Atlv ctlv;
- gint len;
- gulong tag;
- guchar cls;
- gint off = 0;
+ switch (anode_def_type (node)) {
+
+ /* Just use the 'parsed' which is automatically set */
+ case EGG_ASN1X_ANY:
+ case EGG_ASN1X_GENERALSTRING:
+ case EGG_ASN1X_OCTET_STRING:
+ return TRUE;
+
+ case EGG_ASN1X_CHOICE:
+ return anode_decode_choice (node, tlv);
+
+ case EGG_ASN1X_SEQUENCE:
+ case EGG_ASN1X_SET:
+ return anode_decode_sequence_or_set (node, tlv);
+
+ case EGG_ASN1X_SEQUENCE_OF:
+ case EGG_ASN1X_SET_OF:
+ return anode_decode_sequence_or_set_of (node, tlv);
+
+ default:
+ return anode_failure (node, "structured value of an unexpected type");
+ }
+}
- definite = (tlv->len >= 0);
- end = tlv->end;
+static gboolean
+anode_decode_one_without_tag (GNode *node,
+ Atlv *tlv,
+ gint flags)
+{
+ gboolean ret;
+ Anode *an;
/* An explicit, wrapped tag */
if (anode_calc_explicit_for_flags (node, flags, NULL)) {
if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) == 0)
return anode_failure (node, "missing context specific tag");
- if (!anode_decode_tlv_for_contents (tlv, TRUE, &ctlv))
- return anode_failure (node, "invalid encoding of child");
+ if (tlv->child == NULL)
+ return anode_failure (node, "missing context specific child");
+ if (tlv->child->next != NULL)
+ return anode_failure (node, "multiple context specific children");
flags &= ~FLAG_TAG;
- if (!anode_decode_anything_for_flags (node, backing, &ctlv, flags))
- return FALSE;
+ ret = anode_decode_one_without_tag (node, tlv->child, flags);
- /* Use most of the child's tlv */
- tlv->cls = ctlv.cls;
- tlv->tag = ctlv.tag;
- tlv->off += ctlv.off;
- tlv->oft = ctlv.off;
- tlv->len = ctlv.len;
- anode_clr_tlv_data (node);
+ /* Structured value */
+ } else if (tlv->cls & ASN1_CLASS_STRUCTURED) {
+ ret = anode_decode_structured (node, tlv, flags);
- /* Other structured types */
+ /* A primitive simple value */
} else {
- switch (anode_def_type (node)) {
- case EGG_ASN1X_ANY:
- if (!anode_decode_struct_any (node, tlv))
- return FALSE;
- break;
- case EGG_ASN1X_CHOICE:
- if (!anode_decode_choice (node, backing, tlv))
- return FALSE;
- break;
- case EGG_ASN1X_GENERALSTRING:
- case EGG_ASN1X_OCTET_STRING:
- if (!anode_decode_struct_string (node, tlv))
- return FALSE;
- break;
- case EGG_ASN1X_SEQUENCE:
- case EGG_ASN1X_SET:
- if (!anode_decode_sequence_or_set (node, backing, tlv))
- return FALSE;
- break;
- case EGG_ASN1X_SEQUENCE_OF:
- case EGG_ASN1X_SET_OF:
- if (!anode_decode_sequence_or_set_of (node, backing, tlv))
- return FALSE;
- break;
- default:
- return FALSE;
- }
- }
-
- g_return_val_if_fail (tlv->len >= 0, FALSE);
-
- /* Indefinite, needs to be terminated with zeros */
- if (!definite) {
- if (!anode_decode_cls_tag_len (tlv->buf + (tlv->off + tlv->len), end,
- &cls, &tag, &off, &len))
- return anode_failure (node, "end of indefinite content is missing");
- if (!anode_check_indefinite_end (cls, tag, len))
- return anode_failure (node, "end of indefinite content is invalid");
- end = tlv->buf + tlv->off + tlv->len + off;
+ ret = anode_decode_primitive (node, tlv, flags);
}
- /* A structure must be filled up, no stuff ignored */
- if (tlv->buf + tlv->off + tlv->len + off < end)
- return anode_failure (node, "extra data at the end of the content");
- g_return_val_if_fail (tlv->buf + tlv->off + tlv->len + off == end, FALSE);
-
- tlv->end = end;
- anode_set_tlv_data (node, backing, tlv);
- return TRUE;
-}
-
-static gboolean
-anode_decode_option_or_default (GNode *node, Atlv *tlv, gint flags)
-{
- if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
- tlv->len = 0;
- tlv->end = tlv->buf;
- tlv->off = 0;
- anode_clr_tlv_data (node);
- return TRUE;
+ /* Mark which tlv we used for this node */
+ if (ret) {
+ an = node->data;
+ atlv_free (an->parsed);
+ an->parsed = atlv_dup (tlv, FALSE);
}
- return FALSE;
+ return ret;
}
static gboolean
-anode_decode_anything_for_flags (GNode *node,
- GBytes *bytes,
- Atlv *tlv,
- gint flags)
+anode_decode_one (GNode *node,
+ Atlv *tlv)
{
- gboolean ret;
+ gint flags = anode_def_flags (node);
gulong tag;
tag = anode_calc_tag_for_flags (node, flags);
if (tag == G_MAXULONG)
tag = tlv->tag;
- /* Tag does not match, what do we do? */
- if (tlv->off == 0 || tag != tlv->tag) {
- if (anode_decode_option_or_default (node, tlv, flags))
- return TRUE;
+ /* We have no match */
+ if (tag != tlv->tag)
return anode_failure (node, "decoded tag did not match expected");
- }
- /* Structured value */
- if (tlv->cls & ASN1_CLASS_STRUCTURED)
- ret = anode_decode_structured (node, bytes, tlv, flags);
+ return anode_decode_one_without_tag (node, tlv, flags);
+}
- /* A primitive simple value */
- else
- ret = anode_decode_primitive (node, bytes, tlv, flags);
+static gboolean
+anode_decode_option_or_default (GNode *node)
+{
+ gint flags = anode_def_flags (node);
- return ret;
+ if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
+ anode_clr_value (node);
+ return TRUE;
+ }
+
+ return FALSE;
}
static gboolean
anode_decode_anything (GNode *node,
- GBytes *bytes,
Atlv *tlv)
{
- gint flags = anode_def_flags (node);
+ GNode *next;
+ gulong tag;
+ gint flags;
- if (!anode_decode_anything_for_flags (node, bytes, tlv, flags))
- return anode_decode_option_or_default (node, tlv, flags);
+ while (tlv != NULL) {
+ flags = anode_def_flags (node);
+ tag = anode_calc_tag_for_flags (node, flags);
+
+ /* We don't know what the tag is supposed to be */
+ if (tag == G_MAXULONG)
+ tag = tlv->tag;
+
+ /* We have no match */
+ if (tag != tlv->tag) {
+
+ /* See if we can skip this node */
+ if (anode_decode_option_or_default (node))
+ next = g_node_next_sibling (node);
+ else
+ next = NULL;
+
+ if (next == NULL)
+ return anode_failure (node, "decoded tag did not match expected");
+
+ node = next;
+ continue;
+ }
+
+ if (!anode_decode_one_without_tag (node, tlv, flags))
+ return FALSE;
+
+ /* Next node and tag */
+ node = g_node_next_sibling (node);
+ tlv = tlv->next;
+ }
+
+ /* We have no values for these nodes */
+ while (node != NULL) {
+ if (anode_decode_option_or_default (node))
+ node = g_node_next_sibling (node);
+ else
+ return anode_failure (node, "no decoded value");
+ }
return TRUE;
}
gboolean
-egg_asn1x_decode_no_validate (GNode *asn,
- GBytes *data)
+egg_asn1x_decode_full (GNode *asn,
+ GBytes *data,
+ gint options)
{
- const guchar *dat;
- gsize size;
- Atlv tlv;
+ const gchar *msg;
+ gboolean ret;
+ Anode *an;
+ Atlv *tlv;
g_return_val_if_fail (asn != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
egg_asn1x_clear (asn);
- dat = g_bytes_get_data (data, &size);
- g_return_val_if_fail (dat != NULL, FALSE);
-
- if (!anode_decode_tlv_for_data (dat, dat + size, &tlv))
- return anode_failure (asn, "content is not encoded properly");
+ tlv = atlv_new ();
+ msg = atlv_parse_der (data, tlv);
+ if (msg == NULL) {
+ ret = anode_decode_anything (asn, tlv);
- if (!anode_decode_anything (asn, data, &tlv))
- return FALSE;
+ /* A failure, set the message manually so it doesn't get a prefix */
+ } else {
+ an = asn->data;
+ g_free (an->failure);
+ an->failure = g_strdup (msg);
+ ret = FALSE;
+ }
- if (tlv.end - tlv.buf != size)
+ atlv_free (tlv);
+ if (ret == FALSE)
return FALSE;
- return TRUE;
+ return egg_asn1x_validate (asn, !(options & EGG_ASN1X_NO_STRICT));
}
gboolean
egg_asn1x_decode (GNode *asn,
GBytes *data)
{
- gboolean ret;
-
g_return_val_if_fail (asn != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- ret = egg_asn1x_decode_no_validate (asn, data);
- if (!ret)
- return ret;
-
- return egg_asn1x_validate (asn, TRUE);
+ return egg_asn1x_decode_full (asn, data, 0);
}
/* -----------------------------------------------------------------------------------
- * ENCODING
+ * UNPARSE
*/
static void
-anode_encode_length (gulong len, guchar *ans, gint *cb)
+atlv_unparse_len (gulong len,
+ guchar *ans,
+ gint *cb)
{
guchar temp[sizeof (gulong)];
gint k;
}
static gint
-anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
- gulong tag, gint len)
+atlv_unparse_cls_tag_len (guchar *data,
+ gsize n_data,
+ guchar cls,
+ gulong tag,
+ gint len)
{
guchar temp[sizeof(gulong)];
gint cb;
/* And now the length */
cb = n_data - off;
- anode_encode_length (len, data ? data + off : NULL, &cb);
+ atlv_unparse_len (len, data ? data + off : NULL, &cb);
off += cb;
g_assert (!data || n_data >= off);
}
static void
-anode_encode_tlv_and_enc (GNode *node,
- gsize n_data,
- Aencoder encoder,
- gpointer user_data,
- GDestroyNotify destroy)
+atlv_unparse_der (Atlv *tlv,
+ guchar **at,
+ guchar *end)
{
- gboolean explicit = FALSE;
- guchar cls_type;
- gulong tag;
- gint flags;
- Atlv tlv;
-
- g_assert (node);
- g_assert (encoder);
-
- /* The data length */
- memset (&tlv, 0, sizeof (tlv));
- tlv.len = n_data;
-
- /* Figure out the basis if the class */
- switch (anode_def_type (node)) {
- case EGG_ASN1X_INTEGER:
- case EGG_ASN1X_BOOLEAN:
- case EGG_ASN1X_BIT_STRING:
- case EGG_ASN1X_OCTET_STRING:
- case EGG_ASN1X_OBJECT_ID:
- case EGG_ASN1X_TIME:
- case EGG_ASN1X_ENUMERATED:
- case EGG_ASN1X_GENERALSTRING:
- case EGG_ASN1X_NULL:
- tlv.cls = ASN1_CLASS_UNIVERSAL;
- break;
- /* Container types */
- case EGG_ASN1X_SEQUENCE:
- case EGG_ASN1X_SET:
- case EGG_ASN1X_SEQUENCE_OF:
- case EGG_ASN1X_SET_OF:
- tlv.cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_UNIVERSAL);
- break;
+ const guchar *exp;
+ const guchar *buf;
+ guchar *p;
+ guchar mask;
+ Atlv *ctlv;
+ gint off;
+ gsize len;
- /* Transparent types shouldn't get here */
- case EGG_ASN1X_ANY:
- case EGG_ASN1X_CHOICE:
- g_return_if_reached ();
+ g_assert (*at <= end);
- default:
- g_return_if_reached ();
- };
+ off = atlv_unparse_cls_tag_len (*at, end - *at, tlv->cls,
+ tlv->tag, tlv->len);
+ g_assert (off == tlv->off);
+ (*at) += off;
+
+ /* Write a value */
+ if (tlv->value) {
+ buf = g_bytes_get_data (tlv->value, &len);
+ p = *at;
+
+ /* Special behavior for bit strings */
+ if (tlv->prefix_for_bit_string) {
+ g_assert (len + 1 == tlv->len);
+ p[0] = (guchar)tlv->bits_empty;
+ memcpy (p + 1, buf, len);
+
+ /* Set the extra bits to zero */
+ if (len && tlv->bits_empty) {
+ mask = 0xFF >> (8 - tlv->bits_empty);
+ p[len] &= ~mask;
+ }
+ p += len + 1;
- /* Build up the class */
- flags = anode_def_flags (node);
- if (flags & FLAG_TAG) {
- explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
- if (explicit)
- flags &= ~FLAG_TAG;
- else
- tlv.cls |= cls_type;
- }
+ /* Special behavior for prefixed integers */
+ } else if (tlv->prefix_with_zero_byte) {
+ g_assert (len + 1 == tlv->len);
+ p[0] = 0;
+ memcpy (p + 1, buf, len);
+ p += len + 1;
- /* And now the tag */
- tlv.tag = anode_calc_tag_for_flags (node, flags);
+ /* Standard behavior */
+ } else {
+ g_assert (len == tlv->len);
+ memcpy (p, buf, len);
+ p += len;
+ }
- /* Calculate the length for the main thingy */
- tlv.off = anode_encode_cls_tag_len (NULL, 0, tlv.cls, tlv.tag, tlv.len);
+ *at = p;
- /* Wrap that in another explicit tag if necessary */
- if (explicit) {
- tag = anode_calc_tag (node);
- g_return_if_fail (tag != G_MAXULONG);
- tlv.oft = anode_encode_cls_tag_len (NULL, 0, 0, tag, tlv.off + tlv.len);
- tlv.off += tlv.oft;
+ /* Write a bunch of child TLV's */
+ } else {
+ for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+ exp = *at + ctlv->len + ctlv->off;
+ atlv_unparse_der (ctlv, at, end);
+ g_assert (exp == *at);
+ }
}
- /* Not completely filled in */
- tlv.buf = tlv.end = NULL;
-
- anode_clear (node);
- anode_set_tlv_data (node, NULL, &tlv);
- anode_set_enc_data (node, encoder, user_data, destroy);
+ g_assert (*at <= end);
}
-static gboolean
-anode_encode_build (GNode *node,
- GBytes *backing,
- guchar *data,
- gsize n_data)
+static GBytes *
+atlv_unparse_to_bytes (Atlv *tlv,
+ EggAllocator allocator)
{
- guchar cls_type;
- gint type;
- guchar cls;
- gulong tag;
- Aenc *enc;
- Atlv *tlv;
- gint off = 0;
-
- type = anode_def_type (node);
- tlv = anode_get_tlv_data (node);
- g_return_val_if_fail (tlv, FALSE);
-
- /* Should have an encoder */
- enc = anode_get_enc_data (node);
- g_return_val_if_fail (enc, FALSE);
-
- /* If it's a choice node, use the choice for calculations */
- if (type == EGG_ASN1X_CHOICE) {
- node = egg_asn1x_get_choice (node);
- g_return_val_if_fail (node, FALSE);
- }
-
- /* Encode any explicit tag */
- if (anode_calc_explicit (node, &cls_type)) {
- tag = anode_calc_tag (node);
- g_return_val_if_fail (tag != G_MAXULONG, FALSE);
- cls = (ASN1_CLASS_STRUCTURED | cls_type);
- g_assert (tlv->oft > 0 && tlv->oft < tlv->off);
- off = anode_encode_cls_tag_len (data, n_data, cls, tag, (tlv->off - tlv->oft) + tlv->len);
- g_assert (off == tlv->oft);
- }
+ GBytes *bytes;
+ guchar *data;
+ guchar *at;
+ gint len;
- /* Now encode the main tag */
- off += anode_encode_cls_tag_len (data + off, n_data - off, tlv->cls, tlv->tag, tlv->len);
- g_assert (off == tlv->off);
+ /* Allocate enough memory for entire thingy */
+ len = tlv->off + tlv->len;
+ g_return_val_if_fail (len != 0, NULL);
- /* Setup the remainder of the tlv */
- g_assert (tlv->len + tlv->off == n_data);
- tlv->buf = data;
- tlv->end = data + n_data;
- anode_set_backing (node, backing);
+ bytes = bytes_new_with_allocator (allocator, &data, len);
+ if (data == NULL)
+ return NULL;
- /* Encode in the data */
- if (!(enc->encoder) (enc->data, node, data + tlv->off, tlv->len))
- return FALSE;
+ at = data;
+ atlv_unparse_der (tlv, &at, data + len);
+ g_assert (at == data + len);
- return TRUE;
+ return bytes;
}
-static void
-anode_encode_rollback (GNode *node)
-{
- GNode *child;
- Aenc *enc;
+typedef struct {
+ GBytes *bytes;
Atlv *tlv;
-
- /* Undo any references to our new buffer */
- enc = anode_get_enc_data (node);
- if (enc) {
- tlv = anode_get_tlv_data (node);
- g_return_if_fail (tlv);
- tlv->buf = tlv->end = NULL;
- }
-
- for (child = node->children; child; child = child->next)
- anode_encode_rollback (child);
-}
-
-static void
-anode_encode_commit (GNode *node)
-{
- GNode *child;
-
- /* Remove and free all the encoder stuff */
- anode_clr_enc_data (node);
-
- for (child = node->children; child; child = child->next)
- anode_encode_commit (child);
-}
+} SortPair;
static gint
-compare_bufs (gconstpointer a, gconstpointer b)
+compare_sort_pair (gconstpointer a,
+ gconstpointer b)
{
- const Abuf *ba = a;
- const Abuf *bb = b;
- gint res = memcmp (ba->data, bb->data, MIN (ba->n_data, bb->n_data));
- if (ba->n_data == bb->n_data || res != 0)
- return res;
- return ba->n_data < bb->n_data ? -1 : 1;
+ const SortPair *sa = a;
+ const SortPair *sb = b;
+ return g_bytes_compare (sa->bytes, sb->bytes);
}
-static gboolean
-traverse_and_sort_set_of (GNode *node, gpointer user_data)
+static void
+atlv_sort_perform (Atlv *tlv,
+ EggAllocator allocator)
{
- EggAllocator allocator = user_data;
- GList *bufs, *l;
- Abuf *buf;
- guchar *data;
- gsize n_data;
- Atlv *tlv;
- GNode *child;
- GNode *next;
-
- if (!allocator)
- allocator = g_realloc;
-
- /* We have to sort any SET OF :( */
- if (anode_def_type (node) != EGG_ASN1X_SET_OF)
- return FALSE;
+ GList *pairs, *l;
+ SortPair *pair;
+ GBytes *bytes;
+ Atlv *ctlv;
+ Atlv *last;
+ gboolean sort;
- bufs = NULL;
- for (child = node->children; child; child = next) {
- next = child->next;
+ for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next)
+ atlv_sort_perform (ctlv, allocator);
- tlv = anode_get_tlv_data (child);
- if (!tlv)
- continue;
+ if (!tlv->sorted)
+ return;
- /* Allocate enough memory */
- n_data = tlv->len + tlv->off;
- data = (allocator) (NULL, n_data + 1);
- if (!data)
+ pairs = NULL;
+ for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+ bytes = atlv_unparse_to_bytes (ctlv, allocator);
+ if (bytes == NULL)
break;
- if (!anode_encode_build (child, NULL, data, n_data)) {
- (allocator) (data, 0);
- continue;
- }
-
- buf = g_slice_new0 (Abuf);
- buf->user_data = child;
- buf->n_data = n_data;
- buf->data = data;
- bufs = g_list_prepend (bufs, buf);
- g_node_unlink (child);
+ pair = g_slice_new0 (SortPair);
+ pair->bytes = bytes;
+ pair->tlv = ctlv;
+ pairs = g_list_prepend (pairs, pair);
}
- bufs = g_list_sort (bufs, compare_bufs);
+ /* Only sort of the above unparse completed for all */
+ sort = ctlv == NULL;
+ last = NULL;
+
+ pairs = g_list_sort (pairs, compare_sort_pair);
+ for (l = pairs; l != NULL; l = g_list_next (l)) {
+ pair = l->data;
+
+ /* Only if the sort completed */
+ if (sort) {
+ if (last == NULL)
+ tlv->child = pair->tlv;
+ else
+ last->next = pair->tlv;
+ last = pair->tlv;
+ }
- for (l = bufs; l; l = g_list_next (l)) {
- buf = l->data;
- g_node_append (node, buf->user_data);
- (allocator) (buf->data, 0);
- g_slice_free (Abuf, buf);
- }
+ g_bytes_unref (pair->bytes);
+ g_slice_free (SortPair, pair);
+ }
- anode_encode_rollback (node);
- g_list_free (bufs);
- return FALSE;
+ g_list_free (pairs);
}
-static gboolean
-anode_encoder_bytes (gpointer user_data,
- GNode *node,
- guchar *data,
- gsize n_data)
+static void
+anode_build_cls_tag_len (GNode *node,
+ Atlv *tlv,
+ gint len)
{
- GBytes *bytes = user_data;
- g_assert (g_bytes_get_size (bytes) >= n_data);
- memcpy (data, g_bytes_get_data (bytes, NULL), n_data);
- return TRUE;
-}
+ gboolean explicit = FALSE;
+ guchar cls_type;
+ gint flags;
-static gboolean
-anode_encoder_data (gpointer user_data,
- GNode *node,
- guchar *data,
- gsize n_data)
-{
- memcpy (data, user_data, n_data);
- return TRUE;
-}
+ /* One for the prefix character */
+ if (tlv->prefix_for_bit_string ||
+ tlv->prefix_with_zero_byte)
+ len += 1;
-static gboolean
-anode_encoder_unsigned (gpointer user_data,
- GNode *node,
- guchar *data,
- gsize n_data)
-{
- GBytes *value = user_data;
- gboolean sign;
- const gchar *p;
+ /* Figure out the basis if the class */
+ switch (anode_def_type (node)) {
+ case EGG_ASN1X_INTEGER:
+ case EGG_ASN1X_BOOLEAN:
+ case EGG_ASN1X_BIT_STRING:
+ case EGG_ASN1X_OCTET_STRING:
+ case EGG_ASN1X_OBJECT_ID:
+ case EGG_ASN1X_TIME:
+ case EGG_ASN1X_ENUMERATED:
+ case EGG_ASN1X_GENERALSTRING:
+ case EGG_ASN1X_NULL:
+ tlv->cls = ASN1_CLASS_UNIVERSAL;
+ break;
+ /* Container types */
+ case EGG_ASN1X_SEQUENCE:
+ case EGG_ASN1X_SET:
+ case EGG_ASN1X_SEQUENCE_OF:
+ case EGG_ASN1X_SET_OF:
+ tlv->cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_UNIVERSAL);
+ break;
- /*
- * If top bit is set, the result would be negative in two's complement
- * but since we want an unsigned integer, add a zero byte. That zero
- * byte is already calculated into n_data, see egg_asn1x_set_integer_as_usg
- */
+ /* Transparent types shouldn't get here */
+ case EGG_ASN1X_ANY:
+ case EGG_ASN1X_CHOICE:
+ default:
+ g_assert_not_reached ();
+ };
- p = g_bytes_get_data (value, NULL);
- g_return_val_if_fail (p != NULL, FALSE);
+ flags = anode_def_flags (node);
- sign = !!(p[0] & 0x80);
- if (sign) {
- g_assert (n_data > 1);
- data[0] = 0;
- data++;
- n_data--;
+ /* Build up the class */
+ if (flags & FLAG_TAG) {
+ explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
+ if (explicit)
+ flags &= ~FLAG_TAG;
+ else
+ tlv->cls |= cls_type;
}
- memcpy (data, p, n_data);
- return TRUE;
+ /* Setup the class */
+ tlv->tag = anode_calc_tag_for_flags (node, flags);
+
+ /* The offset and length */
+ tlv->len = len;
+ tlv->off = atlv_unparse_cls_tag_len (NULL, 0, tlv->cls, tlv->tag, len);
}
-static gboolean
-anode_encoder_structured (gpointer user_data,
- GNode *unused,
- guchar *data,
- gsize n_data)
+static Atlv *
+anode_build_value (GNode *node)
{
- GNode *node = user_data;
- GNode *child;
- gsize length;
+ Anode *an = node->data;
Atlv *tlv;
+ gsize len;
- for (child = node->children; child; child = child->next) {
- tlv = anode_get_tlv_data (child);
- if (tlv) {
- length = tlv->off + tlv->len;
- g_assert (length <= n_data);
- if (!anode_encode_build (child, anode_get_backing (node),
- data, length))
- return FALSE;
- data += length;
- n_data -= length;
- }
- }
+ /* Fill this in based on the value */
+ if (an->value == NULL)
+ return NULL;
- return TRUE;
+ tlv = atlv_new ();
+ tlv->value = g_bytes_ref (an->value);
+
+ len = g_bytes_get_size (an->value);
+ anode_build_cls_tag_len (node, tlv, len);
+ return tlv;
}
-static gboolean
-anode_encoder_choice (gpointer user_data,
- GNode *unused,
- guchar *data,
- gsize n_data)
+static Atlv *
+anode_build_bit_string (GNode *node)
{
- GNode *node = user_data;
- Aenc *enc = NULL;
- GNode *child;
- Atlv *tlv, *ctlv;
-
- tlv = anode_get_tlv_data (node);
- g_return_val_if_fail (tlv, FALSE);
-
- child = egg_asn1x_get_choice (node);
- g_return_val_if_fail (child, FALSE);
-
- ctlv = anode_get_tlv_data (child);
- g_assert (ctlv);
+ Anode *an = node->data;
+ Atlv *tlv;
+ gsize len;
- enc = anode_get_enc_data (child);
- g_return_val_if_fail (enc, FALSE);
- if (!(enc->encoder) (enc->data, child, data, n_data))
- return FALSE;
+ if (an->value == NULL)
+ return NULL;
- /* Child's buffer matches ours */
- ctlv->buf = tlv->buf;
- ctlv->end = tlv->end;
+ tlv = atlv_new ();
+ tlv->value = g_bytes_ref (an->value);
+ tlv->bits_empty = an->bits_empty;
+ tlv->prefix_for_bit_string = 1;
- return TRUE;
+ len = g_bytes_get_size (an->value);
+ anode_build_cls_tag_len (node, tlv, len);
+ return tlv;
}
-static gboolean
-anode_encoder_bit_string (gpointer user_data,
- GNode *node,
- guchar *data,
- gsize n_data)
+static Atlv *
+anode_build_integer (GNode *node)
{
- Abits *ab = user_data;
- guchar empty, mask;
+ Anode *an = node->data;
+ const guchar *buf;
+ gboolean sign;
gsize len;
+ Atlv *tlv;
- empty = ab->n_bits % 8;
- if (empty > 0)
- empty = 8 - empty;
- len = (ab->n_bits / 8) + (empty ? 1 : 0);
- g_assert (n_data == len + 1);
+ if (an->value == NULL)
+ return NULL;
- /* Fill in the amount of empty */
- data[0] = empty;
- data += 1;
+ tlv = atlv_new ();
+ tlv->value = g_bytes_ref (an->value);
- /* Fill in the actual data */
- memcpy (data, g_bytes_get_data (ab->bits, NULL), len);
+ buf = g_bytes_get_data (an->value, &len);
+ if (an->guarantee_unsigned) {
- /* Set the extra bits to zero */
- if (len && empty) {
- mask = 0xFF >> (8 - empty);
- data[len - 1] &= ~mask;
+ /*
+ * In two's complement (which DER is) this would be negative, add a zero
+ * byte so that it isn't. Here we just note that the result will be one
+ * byte longer.
+ */
+ sign = !!(buf[0] & 0x80);
+ if (sign)
+ tlv->prefix_with_zero_byte = 1;
}
- return TRUE;
+ anode_build_cls_tag_len (node, tlv, len);
+ return tlv;
}
-static gboolean
-anode_encode_prepare_simple (GNode *node, gboolean want)
+static Atlv *
+anode_build_any (GNode *node)
{
- GBytes *backing;
- GBytes *bytes;
- Aenc *enc;
- Atlv *tlv;
+ Atlv *parsed;
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL)
- return FALSE;
-
- /* Transfer the tlv data over to enc */
- enc = anode_get_enc_data (node);
- if (enc == NULL) {
- backing = anode_get_backing (node);
- if (backing == NULL)
- return FALSE;
+ /* Fill this in based on already parsed TLVs */
+ parsed = anode_get_parsed (node);
+ if (parsed != NULL)
+ return atlv_dup (parsed, FALSE);
- bytes = g_bytes_new_with_free_func ((guchar *)tlv->buf + tlv->off, tlv->len,
- (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
- anode_set_enc_data (node, anode_encoder_bytes, bytes,
- (GDestroyNotify)g_bytes_unref);
- }
-
- tlv->buf = tlv->end = NULL;
- return TRUE;
+ return NULL;
}
-static gboolean
-anode_encode_prepare_choice (GNode *node, gboolean want)
+static Atlv *
+anode_build_choice (GNode *node,
+ gboolean want)
{
- Atlv *tlv;
GNode *child;
g_assert (anode_def_type (node) == EGG_ASN1X_CHOICE);
if (!child)
return FALSE;
- if (!anode_encode_prepare (child, want))
- return FALSE;
-
- tlv = anode_get_tlv_data (child);
- g_return_val_if_fail (tlv, FALSE);
- anode_clr_tlv_data (node);
- anode_set_tlv_data (node, NULL, tlv);
- anode_set_enc_data (node, anode_encoder_choice, node, NULL);
-
- return TRUE;
-
+ return anode_build_anything (child, want);
}
-static gboolean
-anode_encode_prepare_structured (GNode *node, gboolean want)
+static Atlv *
+anode_build_structured (GNode *node,
+ gboolean want)
{
gboolean child_want;
- gsize length;
- gboolean had;
+ Atlv *last;
+ Atlv *ctlv;
Atlv *tlv;
GNode *child;
gint type;
+ gint len;
type = anode_def_type (node);
child_want = want;
- had = FALSE;
- length = 0;
+ last = NULL;
+ len = 0;
if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF)
child_want = FALSE;
if (anode_def_flags (node) & FLAG_OPTION)
want = FALSE;
- for (child = node->children; child; child = child->next) {
- if (anode_encode_prepare (child, child_want)) {
- tlv = anode_get_tlv_data (child);
- g_return_val_if_fail (tlv, FALSE);
- length += tlv->off + tlv->len;
- had = TRUE;
+ tlv = atlv_new ();
+ for (child = node->children; child != NULL; child = child->next) {
+ ctlv = anode_build_anything (child, child_want);
+ if (ctlv != NULL) {
+ if (last == NULL)
+ tlv->child = ctlv;
+ else
+ last->next = ctlv;
+ last = ctlv;
+ len += ctlv->off + ctlv->len;
}
}
- if (had == FALSE) {
+ if (last == NULL) {
/* See if we should encode an empty set or seq of */
if (type == EGG_ASN1X_SEQUENCE_OF || type == EGG_ASN1X_SET_OF) {
- if (!want)
- return FALSE;
+ if (!want) {
+ atlv_free (tlv);
+ return NULL;
+ }
} else {
- return FALSE;
+ atlv_free (tlv);
+ return NULL;
}
}
- anode_encode_tlv_and_enc (node, length, anode_encoder_structured, node, NULL);
- return TRUE;
+ anode_build_cls_tag_len (node, tlv, len);
+
+ if (type == EGG_ASN1X_SET_OF)
+ tlv->sorted = 1;
+
+ return tlv;
}
-static gboolean
-anode_encode_prepare (GNode *node, gboolean want)
+static Atlv *
+anode_build_maybe_explicit (GNode *node,
+ Atlv *tlv,
+ gint flags)
{
+ guchar cls_type;
+ Atlv *wrap;
+
+ /* Now wrap in explicit tag if that's the case */
+ if (anode_calc_explicit_for_flags (node, flags, &cls_type)) {
+ wrap = atlv_new ();
+ wrap->cls = (ASN1_CLASS_STRUCTURED | cls_type);
+ wrap->tag = anode_calc_tag (node);
+ wrap->len = tlv->off + tlv->len;
+ wrap->off = atlv_unparse_cls_tag_len (NULL, 0, wrap->cls, wrap->tag, wrap->len);
+ wrap->child = tlv;
+ tlv = wrap;
+ }
+
+ return tlv;
+}
+
+static Atlv *
+anode_build_anything_for_flags (GNode *node,
+ gboolean want,
+ gint flags)
+{
+ Atlv *tlv;
+
switch (anode_def_type (node)) {
+ case EGG_ASN1X_BIT_STRING:
+ tlv = anode_build_bit_string (node);
+ break;
case EGG_ASN1X_INTEGER:
+ tlv = anode_build_integer (node);
+ break;
case EGG_ASN1X_BOOLEAN:
- case EGG_ASN1X_BIT_STRING:
case EGG_ASN1X_OCTET_STRING:
case EGG_ASN1X_OBJECT_ID:
case EGG_ASN1X_TIME:
case EGG_ASN1X_ENUMERATED:
case EGG_ASN1X_GENERALSTRING:
- case EGG_ASN1X_ANY:
case EGG_ASN1X_NULL:
- return anode_encode_prepare_simple (node, want);
+ tlv = anode_build_value (node);
break;
+
+ /* Any should already have explicit tagging */
+ case EGG_ASN1X_ANY:
+ return anode_build_any (node);
+
case EGG_ASN1X_SEQUENCE:
case EGG_ASN1X_SEQUENCE_OF:
case EGG_ASN1X_SET:
case EGG_ASN1X_SET_OF:
- return anode_encode_prepare_structured (node, want);
+ tlv = anode_build_structured (node, want);
break;
+
case EGG_ASN1X_CHOICE:
- return anode_encode_prepare_choice (node, want);
+ tlv = anode_build_choice (node, want);
break;
+
default:
- g_return_val_if_reached (FALSE);
- };
-}
+ g_assert_not_reached ();
+ }
-typedef struct {
- EggAllocator allocator;
- gpointer allocated;
-} AllocatorClosure;
+ if (tlv == NULL)
+ return NULL;
-static void
-destroy_with_allocator (gpointer data)
-{
- AllocatorClosure *closure = data;
- g_assert (closure->allocator);
- (closure->allocator) (closure->allocated, 0);
- g_slice_free (AllocatorClosure, closure);
+ /* Now wrap in explicit tag if that's the case */
+ return anode_build_maybe_explicit (node, tlv, flags);
}
-static GBytes *
-new_bytes_with_allocator (EggAllocator allocator,
- guchar **data,
- gsize length)
+static Atlv *
+anode_build_anything (GNode *node,
+ gboolean want)
{
- AllocatorClosure *closure;
-
- if (allocator) {
- *data = (allocator) (NULL, length + 1);
- if (allocator == NULL)
- return NULL;
- closure = g_slice_new (AllocatorClosure);
- closure->allocated = *data;
- closure->allocator = allocator;
- return g_bytes_new_with_free_func (*data, length,
- destroy_with_allocator,
- closure);
- } else {
- *data = g_malloc (length);
- return g_bytes_new_take (*data, length);
- }
+ return anode_build_anything_for_flags (node, want,
+ anode_def_flags (node));
}
GBytes *
EggAllocator allocator)
{
GBytes *bytes;
- guchar *data;
- gsize length;
Atlv *tlv;
g_return_val_if_fail (asn != NULL, NULL);
g_return_val_if_fail (anode_def_type_is_real (asn), NULL);
- if (!anode_encode_prepare (asn, TRUE)) {
- anode_failure (asn, "missing value(s)");
+ if (!egg_asn1x_validate (asn, TRUE))
return NULL;
- }
-
- /* We must sort all the nasty SET OF nodes */
- g_node_traverse (asn, G_POST_ORDER, G_TRAVERSE_ALL, -1,
- traverse_and_sort_set_of, allocator);
- tlv = anode_get_tlv_data (asn);
- g_return_val_if_fail (tlv, NULL);
-
- /* Allocate enough memory for entire thingy */
- length = tlv->off + tlv->len;
- bytes = new_bytes_with_allocator (allocator, &data, length);
- if (data == NULL)
+ tlv = anode_build_anything (asn, TRUE);
+ if (tlv == NULL) {
+ anode_failure (asn, "missing value(s)");
return NULL;
-
- if (anode_encode_build (asn, bytes, data, length) &&
- anode_validate_anything (asn, TRUE)) {
- anode_encode_commit (asn);
- return bytes;
}
- g_bytes_unref (bytes);
- anode_encode_rollback (asn);
- return NULL;
+ atlv_sort_perform (tlv, allocator);
+
+ bytes = atlv_unparse_to_bytes (tlv, allocator);
+ atlv_free (tlv);
+ return bytes;
}
-/* -----------------------------------------------------------------------------------
- * READING, WRITING, GETTING, SETTING
+/* ----------------------------------------------------------------------------
+ * VALUE READ/WRITE
*/
static int
}
static gboolean
-anode_read_time (GNode *node, Atlv *tlv, struct tm *when, glong *value)
+anode_read_time (GNode *node,
+ GBytes *data,
+ struct tm *when,
+ glong *value)
{
- const gchar *data;
+ const gchar *buf;
gboolean ret;
gint offset = 0;
gint flags;
+ gsize len;
- g_assert (when);
- g_assert (value);
+ g_assert (data != NULL);
+ g_assert (when != NULL);
+ g_assert (value != NULL);
flags = anode_def_flags (node);
- data = (gchar*)(tlv->buf + tlv->off);
+ buf = g_bytes_get_data (data, &len);
if (flags & FLAG_GENERALIZED)
- ret = parse_general_time (data, tlv->len, when, &offset);
+ ret = parse_general_time (buf, len, when, &offset);
else if (flags & FLAG_UTC)
- ret = parse_utc_time (data, tlv->len, when, &offset);
+ ret = parse_utc_time (buf, len, when, &offset);
else
g_return_val_if_reached (FALSE);
}
static gboolean
-anode_read_integer_as_ulong (GNode *node, Atlv *tlv, gulong *value)
+anode_read_integer_ulong (GNode *node,
+ GBytes *data,
+ gulong *value)
{
const guchar *p;
+ gsize len;
gsize k;
- if (tlv->len < 1 || tlv->len > sizeof (gulong))
+ p = g_bytes_get_data (data, &len);
+ if (len < 1 || len > sizeof (gulong))
return FALSE;
- p = tlv->buf + tlv->off;
*value = 0;
- for (k = 0; k < tlv->len; ++k)
- *value |= p[k] << (8 * ((tlv->len - 1) - k));
+ for (k = 0; k < len; ++k)
+ *value |= p[k] << (8 * ((len - 1) - k));
return TRUE;
}
-static gboolean
-anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data)
+static void
+anode_write_integer_ulong (gulong value,
+ guchar *data,
+ gsize *n_data)
{
guchar buf[sizeof (gulong)];
gint bytes, i, off;
buf[i] = (value >> (off * 8)) & 0xFF;
}
- for (bytes = sizeof (gulong) - 1; bytes >= 0; --bytes)
- if (!buf[bytes])
- break;
+ for (bytes = sizeof (gulong) - 1; bytes >= 0; --bytes)
+ if (!buf[bytes])
+ break;
+
+ bytes = sizeof (gulong) - (bytes + 1);
+ if (bytes == 0)
+ bytes = 1;
+
+ /* If the first byte would make this negative, then add a zero */
+ at = buf + (sizeof (gulong) - bytes);
+ sign = !!(at[0] & 0x80);
+
+ if (data) {
+ g_assert (*n_data >= bytes + 1);
+ if (sign) {
+ data[0] = 0;
+ data++;
+ }
+ memcpy (data, at, bytes);
+ }
+
+ *n_data = bytes + (sign ? 1 : 0);
+}
+
+static GBytes *
+anode_default_integer (GNode *node)
+{
+ const gchar *defval;
+ EggAsn1xDef *opt;
+ gchar *end;
+ gulong value;
+ guchar *data;
+ gsize len;
+
+ if (!(anode_def_flags (node) & FLAG_DEFAULT))
+ return NULL;
+
+ /* Try to get a default */
+ opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
+ g_return_val_if_fail (opt != NULL, NULL);
+ g_return_val_if_fail (opt->value != NULL, NULL);
+ defval = opt->value;
+
+ opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, defval);
+ if (opt != NULL) {
+ g_return_val_if_fail (opt->value != NULL, NULL);
+ defval = opt->value;
+ }
+
+ /* Parse out the default value */
+ value = strtoul (defval, &end, 10);
+ g_return_val_if_fail (end && !end[0], NULL);
- bytes = sizeof (gulong) - (bytes + 1);
- if (bytes == 0)
- bytes = 1;
+ anode_write_integer_ulong (value, NULL, &len);
+ data = g_malloc (len);
+ anode_write_integer_ulong (value, data, &len);
+ return g_bytes_new_take (data, len);
+}
- /* If the first byte would make this negative, then add a zero */
- at = buf + (sizeof (gulong) - bytes);
- sign = !!(at[0] & 0x80);
+static gboolean
+anode_read_string_struct (GNode *node,
+ Atlv *tlv,
+ gpointer value,
+ gsize *n_value)
+{
+ const guchar *buf;
+ gsize len;
+ Atlv *ctlv;
+ guchar *at;
+ gint remaining;
- if (data) {
- g_assert (*n_data >= bytes + 1);
- if (sign) {
- data[0] = 0;
- data++;
+ g_assert (tlv != NULL);
+ g_assert (tlv->cls & ASN1_CLASS_STRUCTURED);
+ g_assert (n_value != NULL);
+
+ at = value;
+ remaining = *n_value;
+ *n_value = 0;
+
+ for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) {
+ if (ctlv->cls & ASN1_CLASS_STRUCTURED ||
+ ctlv->value == NULL)
+ return FALSE;
+ buf = g_bytes_get_data (ctlv->value, &len);
+ *n_value += len;
+ if (value) {
+ if (remaining >= len)
+ memcpy (at, buf, len);
+ at += len;
+ remaining -= len;
}
- memcpy (data, at, bytes);
}
- *n_data = bytes + (sign ? 1 : 0);
+ if (value && remaining < 0)
+ return FALSE;
+
return TRUE;
}
static gboolean
-anode_read_string (GNode *node, Atlv *tlv, gpointer value, gsize *n_value)
+anode_read_string_simple (GNode *node,
+ GBytes *data,
+ gpointer value,
+ gsize *n_value)
{
- Atlv ctlv;
- guchar *buf;
- gint n_buf;
- gint i;
-
- g_assert (tlv);
- g_assert (n_value);
+ const guchar *buf;
+ gsize len;
- buf = value;
- n_buf = *n_value;
+ g_assert (data != NULL);
+ g_assert (n_value != NULL);
- /* Is it constructed ? */
- if (tlv->cls & ASN1_CLASS_STRUCTURED) {
- *n_value = 0;
- for (i = 0; TRUE; ++i) {
- if (!anode_decode_tlv_for_contents (tlv, i == 0, &ctlv))
- return anode_failure (node, "invalid encoding of child");
- if (ctlv.off == 0)
- break;
- if (ctlv.cls & ASN1_CLASS_STRUCTURED)
- return FALSE;
- *n_value += ctlv.len;
- if (buf) {
- if (n_buf >= ctlv.len)
- memcpy (buf, ctlv.buf + ctlv.off, ctlv.len);
- buf += ctlv.len;
- n_buf -= ctlv.len;
- }
- }
- if (n_buf < 0)
+ buf = g_bytes_get_data (data, &len);
+ if (value) {
+ if (*n_value < len) {
+ *n_value = len;
return FALSE;
-
- /* Primitive, just return the contents */
- } else {
- *n_value = tlv->len;
- if (buf) {
- if (n_buf < tlv->len)
- return FALSE;
- memcpy (buf, tlv->buf + tlv->off, tlv->len);
}
+ memcpy (value, buf, len);
}
+ *n_value = len;
return TRUE;
}
static gboolean
-anode_read_boolean (GNode *node, Atlv *tlv, gboolean *value)
+anode_read_boolean (GNode *node,
+ GBytes *data,
+ gboolean *value)
{
- g_assert (node);
- g_assert (tlv);
- g_assert (value);
+ const guchar *buf;
+ gsize len;
+
+ g_assert (node != NULL);
+ g_assert (data != NULL);
+ g_assert (value != NULL);
- if (tlv->len != 1)
+ buf = g_bytes_get_data (data, &len);
+ if (len != 1)
return FALSE;
- if (tlv->buf[tlv->off] == 0x00)
+ if (buf[0] == 0x00)
*value = FALSE;
- else if (tlv->buf[tlv->off] == 0xFF)
+ else if (buf[0] == 0xFF)
*value = TRUE;
else
return FALSE;
return TRUE;
}
-static gboolean
-anode_write_boolean (gboolean value, guchar *data, gsize *n_data)
+static void
+anode_write_boolean (gboolean value,
+ guchar *data,
+ gsize *n_data)
{
if (data) {
g_assert (*n_data >= 1);
data[0] = 0x00;
}
*n_data = 1;
- return TRUE;
+}
+
+static GBytes *
+anode_default_boolean (GNode *node)
+{
+ EggAsn1xDef *opt;
+ gboolean value;
+ guchar *data;
+ gsize len;
+
+ if (!(anode_def_flags (node) & FLAG_DEFAULT))
+ return NULL;
+
+ /* Try to get a default */
+ opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
+ g_return_val_if_fail (opt != NULL, NULL);
+
+ /* Parse out the default value */
+ if ((opt->type & FLAG_TRUE) == FLAG_TRUE)
+ value = TRUE;
+ else if ((opt->type & FLAG_FALSE) == FLAG_FALSE)
+ value = FALSE;
+ else
+ g_return_val_if_reached (FALSE);
+
+ anode_write_boolean (value, NULL, &len);
+ data = g_malloc (len);
+ anode_write_boolean (value, data, &len);
+ return g_bytes_new_take (data, len);
}
static gboolean
-anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
+anode_read_object_id (GNode *node,
+ GBytes *data,
+ gchar **oid)
{
GString *result = NULL;
const guchar *p;
gboolean lead;
guint val, pval;
+ gsize len;
gint k;
- g_assert (tlv);
- if (tlv->len <= 0)
- return FALSE;
- p = tlv->buf + tlv->off;
+ g_assert (data != NULL);
+ p = g_bytes_get_data (data, &len);
if (oid)
result = g_string_sized_new (32);
g_string_append_printf (result, "%u.%u", pval, val);
/* TODO: Validate first byte? */
- for (k = 1, lead = 1, val = 0, pval = 0; k < tlv->len; ++k) {
+ for (k = 1, lead = 1, val = 0, pval = 0; k < len; ++k) {
/* X.690: the leading byte must never be 0x80 */
if (lead && p[k] == 0x80) {
anode_failure (node, "object id encoding is invalid");
}
}
- if (k < tlv->len) {
+ if (k < len) {
if (result)
g_string_free (result, TRUE);
return FALSE;
}
static gboolean
-anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
+anode_write_object_id (const gchar *oid,
+ guchar *data,
+ gsize *n_data)
{
const gchar *p, *next;
gint num, num1;
return TRUE;
}
+/* -----------------------------------------------------------------------------------
+ * GETTING, SETTING
+ */
+
GNode*
egg_asn1x_node (GNode *asn, ...)
{
const gchar*
egg_asn1x_name (GNode *node)
{
- g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (node != NULL, NULL);
return anode_def_name (node);
}
EggAsn1xType
egg_asn1x_type (GNode *node)
{
- g_return_val_if_fail (node, 0);
+ g_return_val_if_fail (node != NULL, 0);
return anode_def_type (node);
}
gboolean
egg_asn1x_have (GNode *node)
{
- Atlv *tlv;
+ GNode *child;
g_return_val_if_fail (node, FALSE);
- /* TODO: Handle default values */
+ if (anode_get_value (node) || anode_get_parsed (node))
+ return TRUE;
+
+ for (child = node->children; child != NULL; child = child->next) {
+ if (egg_asn1x_have (child))
+ return TRUE;
+ }
- tlv = anode_get_tlv_data (node);
- return tlv != NULL && tlv->buf != NULL;
+ return FALSE;
}
gboolean
-egg_asn1x_get_boolean (GNode *node, gboolean *value)
+egg_asn1x_get_boolean (GNode *node,
+ gboolean *value)
{
- EggAsn1xDef *opt;
- Atlv *tlv;
+ gboolean ret;
+ GBytes *data;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (value, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN, FALSE);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL) {
-
- if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
- return FALSE;
-
- /* Try to get a default */
- opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
- g_return_val_if_fail (opt, FALSE);
-
- /* Parse out the default value */
- if ((opt->type & FLAG_TRUE) == FLAG_TRUE)
- *value = TRUE;
- else if ((opt->type & FLAG_FALSE) == FLAG_FALSE)
- *value = FALSE;
- else
- g_return_val_if_reached (FALSE);
- return TRUE;
- }
+ data = anode_get_value (node);
+ if (data == NULL)
+ data = anode_default_boolean (node);
+ else
+ g_bytes_ref (data);
+ if (data == NULL)
+ return FALSE;
- return anode_read_boolean (node, tlv, value);
+ ret = anode_read_boolean (node, data, value);
+ g_bytes_unref (data);
+ return ret;
}
-gboolean
+void
egg_asn1x_set_boolean (GNode *node, gboolean value)
{
- guchar *data;
- gsize n_data;
-
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN, FALSE);
+ GBytes *data, *def;
+ guchar *buf;
+ gsize len;
- /* TODO: Handle default values */
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_BOOLEAN);
+
+ len = 1;
+ buf = g_malloc0 (1);
+ anode_write_boolean (value, buf, &len);
+ data = g_bytes_new_take (buf, len);
+
+ /* If it's equal to default, then clear */
+ def = anode_default_boolean (node);
+ if (def) {
+ if (g_bytes_equal (def, data)) {
+ anode_clr_value (node);
+ g_bytes_unref (data);
+ data = NULL;
+ }
+ g_bytes_unref (def);
+ }
- n_data = 1;
- data = g_malloc0 (1);
- if (!anode_write_boolean (value, data, &n_data))
- return FALSE;
- anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
- return TRUE;
+ if (data != NULL)
+ anode_take_value (node, data);
}
-gboolean
+void
egg_asn1x_set_null (GNode *node)
{
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_NULL, FALSE);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_NULL);
/* Encode zero characters */
- anode_encode_tlv_and_enc (node, 0, anode_encoder_data, "", NULL);
- return TRUE;
+ anode_clr_value (node);
+ anode_set_value (node, g_bytes_new_static ("", 0));
}
GQuark
gchar buf[sizeof (gulong) * 3];
EggAsn1xDef *opt;
gulong val;
- Atlv *tlv;
+ GBytes *data;
- g_return_val_if_fail (node, 0);
+ g_return_val_if_fail (node != NULL, 0);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, 0);
- tlv = anode_get_tlv_data (node);
-
- /* TODO: Defaults */
-
- if (tlv == NULL || tlv->buf == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return 0;
/* TODO: Signed values */
- if (!anode_read_integer_as_ulong (node, tlv, &val))
+ if (!anode_read_integer_ulong (node, data, &val))
return 0;
/* Format that as a string */
return g_quark_from_static_string (opt->name);
}
-gboolean
-egg_asn1x_set_enumerated (GNode *node, GQuark value)
+void
+egg_asn1x_set_enumerated (GNode *node,
+ GQuark value)
{
EggAsn1xDef *opt;
const gchar *name;
gsize n_data;
gulong val;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (value, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED, FALSE);
-
- /* TODO: Handle default values */
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (value != 0);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_ENUMERATED);
name = g_quark_to_string (value);
- g_return_val_if_fail (name, FALSE);
+ g_return_if_fail (name != NULL);
opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, name);
- g_return_val_if_fail (opt && opt->value, FALSE);
+ g_return_if_fail (opt && opt->value);
/* TODO: Signed values */
val = anode_def_value_as_ulong (opt);
- g_return_val_if_fail (val != G_MAXULONG, FALSE);
+ g_return_if_fail (val != G_MAXULONG);
n_data = sizeof (gulong) + 1;
data = g_malloc0 (n_data);
- if (!anode_write_integer_ulong (val, data, &n_data))
- return FALSE;
+ anode_write_integer_ulong (val, data, &n_data);
- anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
- return TRUE;
+ anode_clr_value (node);
+ anode_set_value (node, g_bytes_new_take (data, n_data));
}
gboolean
-egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
+egg_asn1x_get_integer_as_ulong (GNode *node,
+ gulong *value)
{
- const EggAsn1xDef *opt;
- const gchar *defval;
- Atlv *tlv;
- gchar *end;
+ gboolean ret;
+ GBytes *data;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (value, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL) {
-
- if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
- return FALSE;
-
- /* Try to get a default */
- opt = anode_opt_lookup (node, EGG_ASN1X_DEFAULT, NULL);
- g_return_val_if_fail (opt, FALSE);
- g_return_val_if_fail (opt->value, FALSE);
- defval = opt->value;
-
- opt = anode_opt_lookup (node, EGG_ASN1X_CONSTANT, defval);
- if (opt != NULL) {
- g_return_val_if_fail (opt->value, FALSE);
- defval = opt->value;
- }
-
- /* Parse out the default value */
- *value = strtoul (defval, &end, 10);
- g_return_val_if_fail (end && !end[0], FALSE);
- return TRUE;
- }
+ data = anode_get_value (node);
+ if (data == NULL)
+ data = anode_default_integer (node);
+ else
+ g_bytes_ref (data);
+ if (data == NULL)
+ return FALSE;
- return anode_read_integer_as_ulong (node, tlv, value);
+ ret = anode_read_integer_ulong (node, data, value);
+ g_bytes_unref (data);
+ return ret;
}
-gboolean
-egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
+void
+egg_asn1x_set_integer_as_ulong (GNode *node,
+ gulong value)
{
- guchar *data;
- gsize n_data;
+ GBytes *data, *def;
+ guchar *buf;
+ gsize len;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
- /* TODO: Handle default values */
+ len = sizeof (gulong) + 1;
+ buf = g_malloc0 (len);
+ anode_write_integer_ulong (value, buf, &len);
+ data = g_bytes_new_take (buf, len);
+
+ /* If it's equal to default, then clear */
+ def = anode_default_integer (node);
+ if (def) {
+ if (g_bytes_equal (def, data)) {
+ anode_clr_value (node);
+ g_bytes_unref (data);
+ data = NULL;
+ }
+ g_bytes_unref (def);
+ }
- n_data = sizeof (gulong) + 1;
- data = g_malloc0 (n_data);
- if (!anode_write_integer_ulong (value, data, &n_data))
- return FALSE;
- anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
- return TRUE;
+ if (data != NULL)
+ anode_take_value (node, data);
}
GBytes *
egg_asn1x_get_integer_as_raw (GNode *node)
{
- GBytes *backing;
- Atlv *tlv;
-
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
+ Anode *an;
+ GBytes *raw;
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
- return NULL;
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, NULL);
- backing = anode_get_backing (node);
- if (backing == NULL)
+ an = node->data;
+ if (an->guarantee_unsigned) {
+ g_warning ("cannot read integer set with egg_asn1x_set_integer_as_raw() "
+ "via egg_asn1x_get_integer_as_raw()");
return NULL;
+ }
- return g_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
- (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
+ raw = anode_get_value (node);
+ if (raw != NULL)
+ g_bytes_ref (raw);
+ return raw;
}
GBytes *
egg_asn1x_get_integer_as_usg (GNode *node)
{
- GBytes *backing;
const guchar *p;
+ Anode *an;
gboolean sign;
- Atlv *tlv;
- gsize n_data;
gsize len;
g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER, FALSE);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
- return NULL;
-
- backing = anode_get_backing (node);
- if (backing == NULL)
- return NULL;
-
- p = tlv->buf + tlv->off;
- len = tlv->len;
-
- sign = !!(p[0] & 0x80);
- if (sign) {
- g_warning ("invalid two's complement integer is negative, but expected unsigned");
+ an = node->data;
+ if (an->value == NULL)
return NULL;
- }
- n_data = len;
+ p = g_bytes_get_data (an->value, &len);
- /* Strip off the extra zero byte that was preventing it from being negative */
- if (p[0] == 0 && len > 1) {
- sign = !!(p[1] & 0x80);
+ if (!an->guarantee_unsigned) {
+ sign = !!(p[0] & 0x80);
if (sign) {
- p++;
- n_data = len - 1;
+ g_warning ("invalid two's complement integer is negative, but expected unsigned");
+ return NULL;
+ }
+
+ /* Strip off the extra zero byte that was preventing it from being negative */
+ if (p[0] == 0 && len > 1) {
+ sign = !!(p[1] & 0x80);
+ if (sign) {
+ p++;
+ len--;
+ }
}
}
- return g_bytes_new_with_free_func (p, n_data,
+ return g_bytes_new_with_free_func (p, len,
(GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
+ g_bytes_ref (an->value));
}
void
{
gboolean sign;
const guchar *p;
+ Anode *an;
+
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+
+ /* Make sure the integer is properly encoded in twos complement*/
+ p = g_bytes_get_data (value, NULL);
+ g_return_if_fail (p != NULL);
+
+ sign = !!(p[0] & 0x80);
+ if (sign) {
+ g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
+ return;
+ }
+
+ anode_clr_value (node);
+ anode_set_value (node, value);
+
+ an = node->data;
+ an->guarantee_unsigned = 0;
+}
+
+void
+egg_asn1x_set_integer_as_usg (GNode *node,
+ GBytes *value)
+{
+ g_return_if_fail (value != NULL);
+ egg_asn1x_take_integer_as_usg (node, g_bytes_ref (value));
+}
+
+void
+egg_asn1x_take_integer_as_usg (GNode *node,
+ GBytes *value)
+{
+ Anode *an;
+
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+
+ anode_set_value (node, value);
+ an = node->data;
+ an->guarantee_unsigned = 1;
+}
+
+GNode *
+egg_asn1x_get_any_as (GNode *node,
+ const EggAsn1xDef *defs,
+ const gchar *type)
+{
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
+ g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, NULL);
+
+ return egg_asn1x_get_any_as_full (node, defs, type, 0);
+}
+
+GNode *
+egg_asn1x_get_any_as_full (GNode *node,
+ const EggAsn1xDef *defs,
+ const gchar *type,
+ gint options)
+{
+ GNode *asn;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
+ g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, NULL);
+
+ asn = egg_asn1x_create (defs, type);
+ g_return_val_if_fail (asn != NULL, NULL);
+
+ if (!egg_asn1x_get_any_into_full (node, asn, options)) {
+ egg_asn1x_destroy (asn);
+ return NULL;
+ }
+
+ return asn;
+}
+
+gboolean
+egg_asn1x_get_any_into (GNode *node,
+ GNode *into)
+{
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (into != NULL, FALSE);
+ g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, FALSE);
+
+ return egg_asn1x_get_any_into_full (node, into, 0);
+}
+
+gboolean
+egg_asn1x_get_any_into_full (GNode *node,
+ GNode *into,
+ gint options)
+{
+ Atlv *tlv;
- g_return_if_fail (node != NULL);
- g_return_if_fail (value != NULL);
- g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (into != NULL, FALSE);
+ g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, FALSE);
- /* Make sure the integer is properly encoded in twos complement*/
- p = g_bytes_get_data (value, NULL);
- g_return_if_fail (p != NULL);
+ tlv = anode_get_parsed (node);
+ if (tlv == NULL)
+ return FALSE;
- sign = !!(p[0] & 0x80);
- if (sign) {
- g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
- return;
+ /* If this node is explicit, then just get the contents */
+ if (anode_calc_explicit_for_flags (node, anode_def_flags (node), NULL)) {
+ tlv = tlv->child;
+ if (tlv == NULL)
+ return FALSE;
}
- anode_encode_tlv_and_enc (node, g_bytes_get_size (value), anode_encoder_bytes,
- value, (GDestroyNotify)g_bytes_unref);
-}
+ if (!anode_decode_anything (into, tlv))
+ return FALSE;
-void
-egg_asn1x_set_integer_as_usg (GNode *node,
- GBytes *value)
-{
- g_return_if_fail (value != NULL);
- egg_asn1x_take_integer_as_usg (node, g_bytes_ref (value));
+ return egg_asn1x_validate (into, !(options & EGG_ASN1X_NO_STRICT));
}
void
-egg_asn1x_take_integer_as_usg (GNode *node,
- GBytes *value)
+egg_asn1x_set_any_from (GNode *node,
+ GNode *from)
{
- gboolean sign;
- const guchar *p;
- gsize len;
+ Anode *an;
+ Atlv *tlv;
g_return_if_fail (node != NULL);
- g_return_if_fail (value != NULL);
- g_return_if_fail (anode_def_type (node) == EGG_ASN1X_INTEGER);
+ g_return_if_fail (from != NULL);
+ g_return_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY);
- /* Make sure the integer is properly encoded in twos complement*/
- p = g_bytes_get_data (value, &len);
- g_return_if_fail (p != NULL);
-
- sign = !!(p[0] & 0x80);
+ tlv = anode_build_anything (from, TRUE);
+ g_return_if_fail (tlv != NULL);
- /*
- * If in two's complement this would be negative, add a zero byte so
- * that it isn't. Here we just note that the result will be one byte
- * longer. In anode_encoder_unsigned we actually add the zero byte.
- */
- if (sign)
- len += 1;
+ /* Wrap this if necessary */
+ tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node));
- anode_encode_tlv_and_enc (node, len, anode_encoder_unsigned,
- value, (GDestroyNotify)g_bytes_unref);
+ /* Mark down the tlvs for this node */
+ an = node->data;
+ atlv_free (an->parsed);
+ an->parsed = tlv;
}
GBytes *
-egg_asn1x_get_element_raw (GNode *node)
+egg_asn1x_get_any_raw (GNode *node,
+ EggAllocator allocator)
{
- GBytes *backing;
- const guchar *p;
- gsize len;
+ GBytes *bytes;
Atlv *tlv;
g_return_val_if_fail (node != NULL, NULL);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
+ tlv = anode_build_anything (node, TRUE);
+ if (tlv == NULL) {
+ anode_failure (node, "missing value(s)");
return NULL;
-
- backing = anode_get_backing (node);
- if (backing == NULL)
- return NULL;
-
- if (anode_calc_explicit (node, NULL)) {
- len = (tlv->len + tlv->off) - tlv->oft;
- p = tlv->buf + tlv->oft;
- } else {
- len = tlv->len + tlv->off;
- p = tlv->buf;
}
- return g_bytes_new_with_free_func (p, len, (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
+ atlv_sort_perform (tlv, allocator);
+
+ bytes = atlv_unparse_to_bytes (tlv, allocator);
+ atlv_free (tlv);
+ return bytes;
}
gboolean
-egg_asn1x_set_element_raw (GNode *node,
- GBytes *element)
+egg_asn1x_set_any_raw (GNode *node,
+ GBytes *raw)
{
- Atlv dtlv, *tlv;
- gint oft, flags;
- const guchar *data;
- guchar cls_type;
- GBytes *sub;
- gsize size;
+ const gchar *msg;
+ Anode *an;
+ Atlv *tlv;
g_return_val_if_fail (node != NULL, FALSE);
- g_return_val_if_fail (element != NULL, FALSE);
-
- anode_clear (node);
- memset (&dtlv, 0, sizeof (dtlv));
+ g_return_val_if_fail (raw != NULL, FALSE);
- data = g_bytes_get_data (element, &size);
- g_return_val_if_fail (data != NULL, FALSE);
+ an = node->data;
+ tlv = atlv_new ();
+ msg = atlv_parse_der (raw, tlv);
+ if (msg == NULL) {
- /* Decode the beginning TLV */
- if (!anode_decode_tlv_for_data (data, data + size, &dtlv))
- return FALSE;
+ /* Wrap this if necessary */
+ tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node));
- /*
- * Decode the data into place properly, to make sure it fits. Note
- * we are not decoding any explicit outer tagging, this is just
- * the internal value. In addition we do not support optional
- * and default values, which would decode successfully in
- * unexpected ways.
- */
- flags = anode_def_flags (node);
- flags &= ~(FLAG_TAG | FLAG_DEFAULT | FLAG_OPTION);
- if (!anode_decode_anything_for_flags (node, element, &dtlv, flags))
- return FALSE;
+ atlv_free (an->parsed);
+ an->parsed = tlv;
+ return TRUE;
- /* There was extra data */
- if (dtlv.end - dtlv.buf != size)
+ /* A failure, set the message manually so it doesn't get a prefix */
+ } else {
+ an = node->data;
+ g_free (an->failure);
+ an->failure = g_strdup (msg);
return FALSE;
-
- /* Clear buffer from TLV so it gets encoded */
- tlv = anode_get_tlv_data (node);
- g_assert (tlv);
- tlv->buf = tlv->end = NULL;
-
- /* Explicit tagging: leave space for the outer tag */
- if (anode_calc_explicit (node, &cls_type)) {
- oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | cls_type),
- anode_calc_tag (node), size);
-
- tlv->off += oft;
- tlv->oft = oft;
}
-
- sub = g_bytes_new_with_free_func (dtlv.buf + dtlv.off, dtlv.len,
- (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (element));
-
- /* Setup encoding of the contents */
- anode_set_enc_data (node, anode_encoder_bytes, sub, (GDestroyNotify)g_bytes_unref);
- return TRUE;
}
GBytes *
-egg_asn1x_get_raw_value (GNode *node)
+egg_asn1x_get_element_raw (GNode *node)
{
- GBytes *backing;
+ Anode *an;
Atlv *tlv;
- g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (node != NULL, NULL);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
- return NULL;
- g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
+ an = node->data;
+ tlv = an->parsed;
+
+ /* If this node is explicit, then just get the contents */
+ if (tlv && anode_calc_explicit_for_flags (node, anode_def_flags (node), NULL))
+ tlv = tlv->child;
- backing = anode_get_backing (node);
- if (backing == NULL)
+ if (!tlv || !tlv->decoded)
return NULL;
- return g_bytes_new_with_free_func (tlv->buf + tlv->off, tlv->len,
- (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
+ return g_bytes_ref (tlv->decoded);
+}
+
+GBytes *
+egg_asn1x_get_value_raw (GNode *node)
+{
+ GBytes *raw;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ raw = anode_get_value (node);
+ if (raw != NULL)
+ g_bytes_ref (raw);
+ return raw;
}
-guchar*
-egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_string)
+guchar *
+egg_asn1x_get_string_as_raw (GNode *node,
+ EggAllocator allocator,
+ gsize *n_string)
{
gsize length;
guchar *string;
+ GBytes *data;
Atlv *tlv;
gint type;
allocator = g_realloc;
type = anode_def_type (node);
- g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, NULL);
+ g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING ||
+ type == EGG_ASN1X_GENERALSTRING, NULL);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
- return NULL;
+ data = anode_get_value (node);
+ if (data != NULL) {
+ if (!anode_read_string_simple (node, data, NULL, &length))
+ return NULL;
- if (!anode_read_string (node, tlv, NULL, &length))
- return NULL;
+ string = (allocator) (NULL, length + 1);
+ if (string == NULL)
+ return NULL;
- string = (allocator) (NULL, length + 1);
- if (string == NULL)
- return NULL;
+ if (!anode_read_string_simple (node, data, string, &length)) {
+ (allocator) (string, 0);
+ return NULL;
+ }
- if (!anode_read_string (node, tlv, string, &length)) {
- (allocator) (string, 0);
- return NULL;
+ /* Courtesy null termination, string must however be validated! */
+ string[length] = 0;
+ *n_string = length;
+ return string;
}
- /* Courtesy null termination, string must however be validated! */
- string[length] = 0;
- *n_string = length;
- return string;
+ tlv = anode_get_parsed (node);
+ if (tlv != NULL) {
+ if (!anode_read_string_struct (node, tlv, NULL, &length))
+ return NULL;
+
+ string = (allocator) (NULL, length + 1);
+ if (string == NULL)
+ return NULL;
+
+ if (!anode_read_string_struct (node, tlv, string, &length)) {
+ (allocator) (string, 0);
+ return NULL;
+ }
+
+ /* Courtesy null termination, string must however be validated! */
+ string[length] = 0;
+ *n_string = length;
+ return string;
+ }
+
+ return NULL;
}
-gboolean
-egg_asn1x_set_string_as_raw (GNode *node, guchar *data, gsize n_data, GDestroyNotify destroy)
+void
+egg_asn1x_set_string_as_raw (GNode *node,
+ guchar *data,
+ gsize n_data,
+ GDestroyNotify destroy)
{
gint type;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (data, FALSE);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (data != NULL);
type = anode_def_type (node);
- g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, FALSE);
+ g_return_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING);
- anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, destroy);
- return TRUE;
+ anode_set_value (node, g_bytes_new_with_free_func (data, n_data,
+ destroy, data));
}
GBytes *
}
gchar*
-egg_asn1x_get_string_as_utf8 (GNode *node, EggAllocator allocator)
+egg_asn1x_get_string_as_utf8 (GNode *node,
+ EggAllocator allocator)
{
gchar *string;
gsize n_string;
}
gboolean
-egg_asn1x_set_string_as_utf8 (GNode *node, gchar *data, GDestroyNotify destroy)
+egg_asn1x_set_string_as_utf8 (GNode *node,
+ gchar *data,
+ GDestroyNotify destroy)
{
gsize n_data;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (data, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
n_data = strlen (data);
if (!g_utf8_validate (data, n_data, NULL))
return FALSE;
- return egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
+ egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
+ return TRUE;
}
GBytes *
-egg_asn1x_get_bits_as_raw (GNode *node, guint *n_bits)
+egg_asn1x_get_bits_as_raw (GNode *node,
+ guint *n_bits)
{
- GBytes *backing;
- guchar padded;
- Atlv *tlv;
-
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (n_bits, FALSE);
- g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
+ gsize len;
+ GBytes *data;
+ Anode *an;
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
- return NULL;
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (n_bits != NULL, NULL);
+ g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, NULL);
- backing = anode_get_backing (node);
- if (backing == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return NULL;
- padded = *(tlv->buf + tlv->off);
- g_return_val_if_fail (padded < 8, NULL);
- g_return_val_if_fail (tlv->len > 1, NULL);
+ len = g_bytes_get_size (data);
+ an = node->data;
- *n_bits = ((tlv->len - 1) * 8) - padded;
- return g_bytes_new_with_free_func (tlv->buf + tlv->off + 1, tlv->len - 1,
- (GDestroyNotify)g_bytes_unref,
- g_bytes_ref (backing));
+ *n_bits = (len * 8) - an->bits_empty;
+ return g_bytes_ref (data);
}
void
GBytes *value,
guint n_bits)
{
+ g_return_if_fail (node != NULL);
g_return_if_fail (value != NULL);
+
egg_asn1x_take_bits_as_raw (node, g_bytes_ref (value), n_bits);
}
GBytes *value,
guint n_bits)
{
+ Anode *an;
gint type;
- gsize length;
- Abits *ab;
+ gsize len;
+ guchar empty;
g_return_if_fail (node != NULL);
g_return_if_fail (value != NULL);
type = anode_def_type (node);
g_return_if_fail (type == EGG_ASN1X_BIT_STRING);
- length = (n_bits / 8);
+ len = (n_bits / 8);
if (n_bits % 8)
- length += 1;
+ len += 1;
- ab = g_slice_new0 (Abits);
- ab->bits = value;
- ab->n_bits = n_bits;
+ empty = n_bits % 8;
+ if (empty > 0)
+ empty = 8 - empty;
- anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+ anode_take_value (node, value);
+ an = node->data;
+ an->bits_empty = empty;
}
gboolean
-egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
+egg_asn1x_get_bits_as_ulong (GNode *node,
+ gulong *bits,
+ guint *n_bits)
{
- Atlv *tlv;
+ GBytes *data;
+ const guchar *buf;
+ gsize len;
guint i, length;
guchar empty;
const guchar *p;
gulong value;
+ Anode *an;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (bits, FALSE);
- g_return_val_if_fail (n_bits, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+ g_return_val_if_fail (bits != NULL, FALSE);
+ g_return_val_if_fail (n_bits != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_BIT_STRING, FALSE);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return FALSE;
- empty = *(tlv->buf + tlv->off);
- g_return_val_if_fail (empty < 8, FALSE);
- g_return_val_if_fail (tlv->len > 1, FALSE);
+ buf = g_bytes_get_data (data, &len);
+ an = node->data;
+ empty = an->bits_empty;
- length = ((tlv->len - 1) * 8) - empty;
+ length = (len * 8) - empty;
if (length > sizeof (gulong) * 8)
return FALSE;
value = 0;
- p = tlv->buf + tlv->off + 1;
+ p = buf;
- for (i = 0; i < tlv->len - 1; ++i)
+ for (i = 0; i < len; ++i)
value = value << 8 | p[i];
*bits = value >> empty;
return TRUE;
}
-gboolean
-egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
+void
+egg_asn1x_set_bits_as_ulong (GNode *node,
+ gulong bits,
+ guint n_bits)
{
guchar *data;
gulong value;
- gint type;
- gsize i, length;
+ gsize i, len;
guchar empty;
- Abits *ab;
+ Anode *an;
+ gint type;
- g_return_val_if_fail (node, FALSE);
- g_return_val_if_fail (bits, FALSE);
- g_return_val_if_fail (n_bits <= sizeof (gulong) * 8, FALSE);
+ g_return_if_fail (node != NULL);
+ g_return_if_fail (n_bits <= sizeof (gulong) * 8);
type = anode_def_type (node);
- g_return_val_if_fail (type == EGG_ASN1X_BIT_STRING, FALSE);
+ g_return_if_fail (type == EGG_ASN1X_BIT_STRING);
empty = n_bits % 8;
if (empty > 0)
empty = 8 - empty;
- length = (n_bits / 8) + (empty ? 1 : 0);
+ len = (n_bits / 8) + (empty ? 1 : 0);
data = g_malloc0 (sizeof (gulong));
value = bits << empty;
- for (i = 0; i < length; ++i)
- data[(length - i) - 1] = (value >> i * 8) & 0xFF;
+ for (i = 0; i < len; ++i)
+ data[len - i - 1] = (value >> i * 8) & 0xFF;
- ab = g_slice_new0 (Abits);
- ab->bits = g_bytes_new_take (data, sizeof (gulong));
- ab->n_bits = n_bits;
-
- anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
- return TRUE;
+ an = node->data;
+ an->bits_empty = empty;
+ anode_take_value (node, g_bytes_new_take (data, len));
}
glong
egg_asn1x_get_time_as_long (GNode *node)
{
struct tm when;
- Atlv *tlv;
+ GBytes *data;
glong time;
gint type;
g_return_val_if_fail (type == EGG_ASN1X_TIME, -1);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return -1;
- if (!anode_read_time (node, tlv, &when, &time))
+ if (!anode_read_time (node, data, &when, &time))
return -1;
return time;
}
gboolean
-egg_asn1x_get_time_as_date (GNode *node, GDate *date)
+egg_asn1x_get_time_as_date (GNode *node,
+ GDate *date)
{
struct tm when;
- Atlv *tlv;
+ GBytes *data;
glong time;
gint type;
g_return_val_if_fail (type == EGG_ASN1X_TIME, FALSE);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return FALSE;
- if (!anode_read_time (node, tlv, &when, &time))
+ if (!anode_read_time (node, data, &when, &time))
return FALSE;
g_date_set_dmy (date, when.tm_mday, when.tm_mon + 1, when.tm_year + 1900);
gchar*
egg_asn1x_get_oid_as_string (GNode *node)
{
+ GBytes *data;
gchar *oid;
- Atlv *tlv;
g_return_val_if_fail (node, NULL);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, NULL);
- tlv = anode_get_tlv_data (node);
- if (tlv == NULL || tlv->buf == NULL)
+ data = anode_get_value (node);
+ if (data == NULL)
return NULL;
- if (!anode_read_object_id (node, tlv, &oid))
+ if (!anode_read_object_id (node, data, &oid))
return NULL;
return oid;
}
gboolean
-egg_asn1x_set_oid_as_string (GNode *node, const gchar *oid)
+egg_asn1x_set_oid_as_string (GNode *node,
+ const gchar *oid)
{
guchar *data;
gsize n_data;
- g_return_val_if_fail (oid, FALSE);
- g_return_val_if_fail (node, FALSE);
+ g_return_val_if_fail (oid != NULL, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_OBJECT_ID, FALSE);
/* Encoding will always be shorter than string */
n_data = strlen (oid);
data = g_malloc0 (n_data);
- if (!anode_write_oid (oid, data, &n_data)) {
+ if (!anode_write_object_id (oid, data, &n_data)) {
g_free (data);
return FALSE;
}
- anode_encode_tlv_and_enc (node, n_data, anode_encoder_data, data, g_free);
+ anode_take_value (node, g_bytes_new_take (data, n_data));
return TRUE;
}
}
gboolean
-egg_asn1x_set_oid_as_quark (GNode *node, GQuark oid)
+egg_asn1x_set_oid_as_quark (GNode *node,
+ GQuark oid)
{
const gchar *str;
- g_return_val_if_fail (oid, FALSE);
+ g_return_val_if_fail (oid != 0, FALSE);
+
str = g_quark_to_string (oid);
- g_return_val_if_fail (str, FALSE);
+ g_return_val_if_fail (str != NULL, FALSE);
return egg_asn1x_set_oid_as_string (node, str);
}
}
gboolean
-egg_asn1x_set_choice (GNode *node, GNode *choice)
+egg_asn1x_set_choice (GNode *node,
+ GNode *choice)
{
GNode *child;
Anode *an;
- g_return_val_if_fail (node, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (anode_def_type (node) == EGG_ASN1X_CHOICE, FALSE);
/* One and only one of the children must be set */
*/
static gboolean
-anode_parse_size (GNode *node, const gchar *text, gulong *value)
+anode_parse_size (GNode *node,
+ const gchar *text,
+ gulong *value)
{
EggAsn1xDef *def;
gchar *end = NULL;
static gboolean
-anode_validate_size (GNode *node, gulong length)
+anode_validate_size (GNode *node,
+ gulong length)
{
EggAsn1xDef *size;
gulong value1 = 0;
}
static gboolean
-anode_validate_integer (GNode *node, Atlv *tlv)
+anode_validate_integer (GNode *node,
+ GBytes *value)
{
GList *constants, *l;
- gulong value, check;
+ gulong val, check;
+ gsize len;
gboolean found;
gint flags;
- g_assert (tlv);
+ g_assert (value != NULL);
+ len = g_bytes_get_size (value);
/* Integers must be at least one byte long */
- if (tlv->len <= 0)
+ if (len == 0)
return anode_failure (node, "zero length integer");
flags = anode_def_flags (node);
if (flags & FLAG_LIST) {
/* Parse out the value, we only support small integers*/
- if (!anode_read_integer_as_ulong (node, tlv, &value))
+ if (!anode_read_integer_ulong (node, value, &val))
return anode_failure (node, "integer not part of list");
/* Look through the list of constants */
for (l = constants; l; l = g_list_next (l)) {
check = anode_def_value_as_ulong (l->data);
g_return_val_if_fail (check != G_MAXULONG, FALSE);
- if (check == value) {
+ if (check == val) {
found = TRUE;
break;
}
}
static gboolean
-anode_validate_enumerated (GNode *node, Atlv *tlv)
+anode_validate_enumerated (GNode *node,
+ GBytes *value)
{
- g_assert (tlv);
+ const guchar *buf;
+ gsize length;
+
+ g_assert (value != NULL);
- if (!anode_validate_integer (node, tlv))
+ if (!anode_validate_integer (node, value))
return FALSE;
- g_assert (tlv->len); /* Checked above */
+
+ buf = g_bytes_get_data (value, &length);
+ g_assert (length > 0); /* Checked above */
+
/* Enumerated must be positive */
- if (tlv->buf[tlv->off] & 0x80)
+ if (buf[0] & 0x80)
return anode_failure (node, "enumerated must be positive");
return TRUE;
}
static gboolean
-anode_validate_boolean (GNode *node, Atlv *tlv)
+anode_validate_boolean (GNode *node,
+ GBytes *value)
{
- g_assert (tlv);
+ const guchar *buf;
+ gsize len;
+
+ g_assert (value != NULL);
+ buf = g_bytes_get_data (value, &len);
/* Must one byte, and zero or all ones */
- if (tlv->len != 1)
+ if (len != 1)
return anode_failure (node, "invalid length boolean");
- if (tlv->buf[tlv->off] != 0x00 && tlv->buf[tlv->off] != 0xFF)
+ if (buf[0] != 0x00 && buf[0] != 0xFF)
return anode_failure (node, "boolean must be true or false");
return TRUE;
}
static gboolean
-anode_validate_bit_string (GNode *node, Atlv *tlv)
+anode_validate_bit_string (GNode *node,
+ GBytes *value)
{
- guchar empty, mask;
- g_assert (tlv);
+ g_assert (value != NULL);
- /* At least two bytes in length */
- if (tlv->len < 1)
- return anode_failure (node, "invalid length bit string");
- /* First byte is the number of free bits at end */
- empty = tlv->buf[tlv->off];
- if (empty > 7)
- return anode_failure (node, "bit string has invalid header");
- /* Free bits at end must be zero */
- mask = 0xFF >> (8 - empty);
- if (tlv->len > 1 && tlv->buf[tlv->off + tlv->len - 1] & mask)
- return anode_failure (node, "bit string has invalid trailing bits");
+ /* All the decode validation done in anode_decode_bit_string */
return TRUE;
}
static gboolean
-anode_validate_string (GNode *node, Atlv *tlv)
+anode_validate_string (GNode *node,
+ GBytes *value)
{
gsize length;
- if (!anode_read_string (node, tlv, NULL, &length))
+ if (!anode_read_string_simple (node, value, NULL, &length))
return anode_failure (node, "string content is invalid");
return anode_validate_size (node, (gulong)length);
}
static gboolean
-anode_validate_object_id (GNode *node, Atlv *tlv)
+anode_validate_object_id (GNode *node,
+ GBytes *value)
{
- return anode_read_object_id (node, tlv, NULL);
+ return anode_read_object_id (node, value, NULL);
}
static gboolean
-anode_validate_null (GNode *node, Atlv *tlv)
+anode_validate_null (GNode *node,
+ GBytes *value)
{
- g_assert (tlv);
- return (tlv->len == 0);
+ g_assert (value != NULL);
+ return (g_bytes_get_size (value) == 0);
}
static gboolean
-anode_validate_time (GNode *node, Atlv *tlv)
+anode_validate_time (GNode *node,
+ GBytes *value)
{
glong time;
struct tm when;
- return anode_read_time (node, tlv, &when, &time);
+ return anode_read_time (node, value, &when, &time);
}
static gboolean
gboolean strict)
{
GNode *child;
- gulong tag = 0;
- gint count = 0;
- gint type;
- Atlv *tlv;
-
- type = anode_def_type (node);
/* All of the children must validate properly */
for (child = node->children; child; child = child->next) {
- if (!anode_validate_anything (child, strict))
- return FALSE;
-
- /* Tags must be in ascending order */
- tlv = anode_get_tlv_data (child);
- if (tlv && type == EGG_ASN1X_SET) {
- if (count > 0 && tag > tlv->tag)
- return anode_failure (node, "content must be in ascending order");
- tag = tlv->tag;
- ++count;
+ if (egg_asn1x_have (child)) {
+ if (!anode_validate_anything (child, strict))
+ return FALSE;
}
}
gboolean strict)
{
GNode *child;
- Atlv *tlv, *ptlv;
- gulong tag;
gulong count;
- gint type;
- tag = 0;
count = 0;
- ptlv = NULL;
-
- type = anode_def_type (node);
/* All the children must validate properly */
for (child = node->children; child; child = child->next) {
- tlv = anode_get_tlv_data (child);
- if (tlv) {
+ if (egg_asn1x_have (child)) {
if (!anode_validate_anything (child, strict))
return FALSE;
-
- /* Tag must have same tag as top */
- if (count == 0)
- tag = anode_calc_tag (child);
- else if (tag != G_MAXULONG && tlv->tag != tag)
- return anode_failure (node, "invalid mismatched content");
-
- /* Set of must be in ascending order */
- if (strict && type == EGG_ASN1X_SET_OF &&
- ptlv != NULL && compare_tlvs (ptlv, tlv) > 0)
- return anode_failure (node, "content must be in ascending order");
- ptlv = tlv;
- ++count;
+ count++;
}
}
anode_validate_anything (GNode *node,
gboolean strict)
{
+ GBytes *value;
Atlv *tlv;
gint type;
type = anode_def_type (node);
- tlv = anode_get_tlv_data (node);
-
- if (!tlv) {
- if (anode_def_flags (node) & FLAG_OPTION)
- return TRUE;
- if (anode_def_flags (node) & FLAG_DEFAULT)
- return TRUE;
- return anode_failure (node, "missing value");
- }
-
- g_return_val_if_fail (tlv->buf, FALSE);
+ /* Handle these specially */
switch (type) {
-
- /* The primitive value types */
- case EGG_ASN1X_INTEGER:
- return anode_validate_integer (node, tlv);
- case EGG_ASN1X_ENUMERATED:
- return anode_validate_enumerated (node, tlv);
- case EGG_ASN1X_BOOLEAN:
- return anode_validate_boolean (node, tlv);
- case EGG_ASN1X_BIT_STRING:
- return anode_validate_bit_string (node, tlv);
- case EGG_ASN1X_OCTET_STRING:
- return anode_validate_string (node, tlv);
- case EGG_ASN1X_OBJECT_ID:
- return anode_validate_object_id (node, tlv);
- case EGG_ASN1X_NULL:
- return anode_validate_null (node, tlv);
- case EGG_ASN1X_GENERALSTRING:
- return anode_validate_string (node, tlv);
- case EGG_ASN1X_TIME:
- return anode_validate_time (node, tlv);
-
- /* Transparent types */
- case EGG_ASN1X_ANY:
- return TRUE;
case EGG_ASN1X_CHOICE:
return anode_validate_choice (node, strict);
- /* Structured types */
case EGG_ASN1X_SEQUENCE:
case EGG_ASN1X_SET:
return anode_validate_sequence_or_set (node, strict);
return anode_validate_sequence_or_set_of (node, strict);
default:
- g_return_val_if_reached (FALSE);
+ break;
+ }
+
+ /* Values that have been configured */
+ value = anode_get_value (node);
+ if (value) {
+ switch (type) {
+ case EGG_ASN1X_INTEGER:
+ return anode_validate_integer (node, value);
+ case EGG_ASN1X_ENUMERATED:
+ return anode_validate_enumerated (node, value);
+ case EGG_ASN1X_BOOLEAN:
+ return anode_validate_boolean (node, value);
+ case EGG_ASN1X_BIT_STRING:
+ return anode_validate_bit_string (node, value);
+ case EGG_ASN1X_OCTET_STRING:
+ return anode_validate_string (node, value);
+ case EGG_ASN1X_OBJECT_ID:
+ return anode_validate_object_id (node, value);
+ case EGG_ASN1X_NULL:
+ return anode_validate_null (node, value);
+ case EGG_ASN1X_GENERALSTRING:
+ return anode_validate_string (node, value);
+ case EGG_ASN1X_TIME:
+ return anode_validate_time (node, value);
+ default:
+ g_assert_not_reached ();
+ }
}
+
+ /* See if there's a tlv parsed */
+ tlv = anode_get_parsed (node);
+ if (tlv) {
+ switch (type) {
+ case EGG_ASN1X_ANY:
+ case EGG_ASN1X_GENERALSTRING:
+ case EGG_ASN1X_OCTET_STRING:
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ if (anode_def_flags (node) & FLAG_OPTION)
+ return TRUE;
+ if (anode_def_flags (node) & FLAG_DEFAULT)
+ return TRUE;
+ return anode_failure (node, "missing value");
}
gboolean
return egg_asn1x_create (defs, g_quark_to_string (type));
}
-GNode*
-egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
- const gchar *identifier,
- GBytes *data)
+GNode *
+egg_asn1x_create_and_decode_full (const EggAsn1xDef *defs,
+ const gchar *identifier,
+ GBytes *data,
+ gint options)
{
GNode *asn;
- g_return_val_if_fail (defs, NULL);
- g_return_val_if_fail (identifier, NULL);
+ g_return_val_if_fail (defs != NULL, NULL);
+ g_return_val_if_fail (identifier != NULL, NULL);
+ g_return_val_if_fail (data != NULL, NULL);
asn = egg_asn1x_create (defs, identifier);
g_return_val_if_fail (asn, NULL);
- if (!egg_asn1x_decode (asn, data)) {
+ if (!egg_asn1x_decode_full (asn, data, options)) {
egg_asn1x_destroy (asn);
return NULL;
}
return asn;
+
+}
+
+GNode*
+egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
+ const gchar *identifier,
+ GBytes *data)
+{
+ g_return_val_if_fail (defs != NULL, NULL);
+ g_return_val_if_fail (identifier != NULL, NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+
+ return egg_asn1x_create_and_decode_full (defs, identifier, data, 0);
}
/* -----------------------------------------------------------------------------------
guint i, depth;
GString *output;
gchar *string;
- Atlv *tlv;
Anode *an;
GList *l;
for (i = 0; i < depth - 1; ++i)
g_printerr (" ");
- tlv = anode_get_tlv_data (node);
+ an = node->data;
output = g_string_new ("");
dump_append_type (output, anode_def_type (node));
dump_append_flags (output, anode_def_flags (node));
string = g_utf8_casefold (output->str, output->len - 1);
g_string_free (output, TRUE);
g_printerr ("+ %s: %s [%s]%s\n", anode_def_name (node), anode_def_value (node),
- string, tlv && tlv->buf ? " *" : "");
+ string, an->parsed || an->value ? " *" : "");
g_free (string);
/* Print out all the options */
- an = node->data;
for (l = an->opts; l; l = g_list_next (l)) {
for (i = 0; i < depth; ++i)
g_printerr (" ");
int cb, len;
gulong tag;
- if (anode_decode_cls_tag (data, data + n_data, &cls, &tag, &cb)) {
+ if (atlv_parse_cls_tag (data, data + n_data, &cls, &tag, &cb)) {
counter += cb;
- len = anode_decode_length (data + cb, data + n_data, &cb);
+ len = atlv_parse_length (data + cb, data + n_data, &cb);
counter += cb;
if (len >= 0) {
len += counter;
g_return_val_if_fail (n_content != NULL, NULL);
/* Now get the data out of this element */
- if (!anode_decode_cls_tag (data, (const guchar*)data + n_data, &cls, &tag, &cb))
+ if (!atlv_parse_cls_tag (data, data + n_data, &cls, &tag, &cb))
return NULL;
counter += cb;
- len = anode_decode_length ((const guchar*)data + cb, (const guchar*)data + n_data, &cb);
+ len = atlv_parse_length (data + cb, data + n_data, &cb);
if (len < 0)
return NULL;
counter += cb;