[gcr] egg: Rework how DER parsing works
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr] egg: Rework how DER parsing works
- Date: Thu, 21 Jun 2012 14:24:43 +0000 (UTC)
commit ae6f001f386df172f966e055516c0b968379804a
Author: Stef Walter <stefw gnome org>
Date: Wed Jun 20 08:15:20 2012 +0200
egg: Rework how DER parsing works
In particular fix things like
* Indefinite parsing
* Encoding of defaults
* Ability to read values that haven't yet been encoded
* Proper handling of ANY tags
egg/egg-asn1x.c | 3170 +++++++++++++------------
egg/egg-asn1x.h | 68 +-
egg/egg-dn.c | 50 +-
egg/egg-dn.h | 4 +-
egg/egg-symkey.c | 74 +-
egg/egg-symkey.h | 4 +-
egg/tests/Makefile.am | 13 +-
egg/tests/files/test-personalname-1.der | 2 +-
egg/tests/files/test-personalname-invalid.der | 1 +
egg/tests/files/test-pkcs12-2.der | Bin 0 -> 2142 bytes
egg/tests/test-asn1.c | 91 +-
egg/tests/test-asn1x.c | 140 +-
egg/tests/test-dn.c | 19 +-
egg/tests/test.asn | 3 +-
gcr/gcr-certificate-extensions.c | 14 +-
gcr/gcr-certificate-renderer.c | 4 +-
gcr/gcr-certificate-request.c | 7 +-
gcr/gcr-parser.c | 190 +-
gcr/gcr-subject-public-key.c | 30 +-
gcr/tests/files/usr0052-firefox.p12 | Bin 0 -> 2142 bytes
gcr/tests/test-parser.c | 3 +
21 files changed, 2001 insertions(+), 1886 deletions(-)
---
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 0fabb74..6fcd48e 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -56,25 +56,28 @@
/* 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 */
@@ -104,31 +107,30 @@ enum {
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 {
@@ -136,31 +138,23 @@ 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)
@@ -175,6 +169,55 @@ 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)
{
@@ -357,110 +400,97 @@ anode_opts_lookup (GNode *node, gint type, const gchar *name)
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
@@ -493,9 +523,7 @@ static void
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;
}
@@ -511,16 +539,6 @@ anode_free_func (GNode *node, gpointer unused)
}
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))
@@ -561,9 +579,9 @@ anode_calc_tag_for_flags (GNode *node, gint flags)
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:
@@ -625,47 +643,43 @@ anode_calc_explicit_for_flags (GNode *node,
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)
@@ -676,13 +690,13 @@ anode_decode_cls_tag (const guchar *data, const guchar *end,
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)
@@ -692,31 +706,33 @@ anode_decode_cls_tag (const guchar *data, const guchar *end,
}
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 */
@@ -724,7 +740,7 @@ anode_decode_length (const guchar *data, const guchar *end, gint *cb)
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)
@@ -736,142 +752,160 @@ anode_decode_length (const guchar *data, const guchar *end, gint *cb)
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;
@@ -880,7 +914,7 @@ anode_decode_choice (GNode *node,
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 {
@@ -895,82 +929,40 @@ anode_decode_choice (GNode *node,
}
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);
@@ -979,15 +971,15 @@ anode_decode_sequence_or_set_of (GNode *node,
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;
@@ -996,171 +988,154 @@ anode_decode_sequence_or_set_of (GNode *node,
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);
@@ -1169,87 +1144,130 @@ anode_decode_anything_for_flags (GNode *node,
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;
@@ -1279,8 +1297,11 @@ anode_encode_length (gulong len, guchar *ans, gint *cb)
}
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;
@@ -1313,7 +1334,7 @@ anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
/* 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);
@@ -1321,422 +1342,311 @@ anode_encode_cls_tag_len (guchar *data, gsize n_data, guchar cls,
}
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);
@@ -1745,127 +1655,143 @@ anode_encode_prepare_choice (GNode *node, gboolean want)
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 *
@@ -1873,44 +1799,29 @@ egg_asn1x_encode (GNode *asn,
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
@@ -2167,23 +2078,28 @@ parse_general_time (const gchar *time, gsize n_time,
}
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);
@@ -2205,24 +2121,29 @@ anode_read_time (GNode *node, Atlv *tlv, struct tm *when, glong *value)
}
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;
@@ -2234,99 +2155,158 @@ anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data)
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);
@@ -2336,22 +2316,51 @@ anode_write_boolean (gboolean value, guchar *data, gsize *n_data)
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);
@@ -2363,7 +2372,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
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");
@@ -2385,7 +2394,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
}
}
- if (k < tlv->len) {
+ if (k < len) {
if (result)
g_string_free (result, TRUE);
return FALSE;
@@ -2397,7 +2406,9 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
}
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;
@@ -2452,6 +2463,10 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
return TRUE;
}
+/* -----------------------------------------------------------------------------------
+ * GETTING, SETTING
+ */
+
GNode*
egg_asn1x_node (GNode *asn, ...)
{
@@ -2507,14 +2522,14 @@ 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);
}
@@ -2569,77 +2584,84 @@ egg_asn1x_append (GNode *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
@@ -2648,21 +2670,18 @@ egg_asn1x_get_enumerated (GNode *node)
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 */
@@ -2677,8 +2696,9 @@ egg_asn1x_get_enumerated (GNode *node)
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;
@@ -2686,156 +2706,143 @@ egg_asn1x_set_enumerated (GNode *node, GQuark value)
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
@@ -2852,183 +2859,244 @@ egg_asn1x_take_integer_as_raw (GNode *node,
{
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;
@@ -3039,43 +3107,68 @@ egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_strin
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 *
@@ -3113,7 +3206,8 @@ egg_asn1x_get_bmpstring_as_utf8 (GNode *node)
}
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;
@@ -3136,47 +3230,44 @@ egg_asn1x_get_string_as_utf8 (GNode *node, EggAllocator allocator)
}
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
@@ -3184,7 +3275,9 @@ egg_asn1x_set_bits_as_raw (GNode *node,
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);
}
@@ -3193,9 +3286,10 @@ egg_asn1x_take_bits_as_raw (GNode *node,
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);
@@ -3203,47 +3297,54 @@ egg_asn1x_take_bits_as_raw (GNode *node,
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;
@@ -3251,47 +3352,45 @@ egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
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;
@@ -3309,20 +3408,21 @@ egg_asn1x_get_time_as_long (GNode *node)
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;
@@ -3340,11 +3440,11 @@ egg_asn1x_get_time_as_date (GNode *node, GDate *date)
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);
@@ -3354,42 +3454,43 @@ egg_asn1x_get_time_as_date (GNode *node, GDate *date)
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;
}
@@ -3408,13 +3509,15 @@ egg_asn1x_get_oid_as_quark (GNode *node)
}
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);
}
@@ -3438,12 +3541,13 @@ egg_asn1x_get_choice (GNode *node)
}
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 */
@@ -3468,7 +3572,9 @@ egg_asn1x_set_choice (GNode *node, GNode *choice)
*/
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;
@@ -3492,7 +3598,8 @@ anode_parse_size (GNode *node, const gchar *text, gulong *value)
static gboolean
-anode_validate_size (GNode *node, gulong length)
+anode_validate_size (GNode *node,
+ gulong length)
{
EggAsn1xDef *size;
gulong value1 = 0;
@@ -3518,23 +3625,26 @@ anode_validate_size (GNode *node, gulong length)
}
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 */
@@ -3543,7 +3653,7 @@ anode_validate_integer (GNode *node, Atlv *tlv)
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;
}
@@ -3558,82 +3668,88 @@ anode_validate_integer (GNode *node, Atlv *tlv)
}
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
@@ -3667,25 +3783,12 @@ anode_validate_sequence_or_set (GNode *node,
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;
}
}
@@ -3697,36 +3800,16 @@ anode_validate_sequence_or_set_of (GNode *node,
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++;
}
}
@@ -3737,51 +3820,17 @@ static gboolean
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);
@@ -3791,8 +3840,54 @@ anode_validate_anything (GNode *node,
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
@@ -4169,25 +4264,40 @@ egg_asn1x_create_quark (const EggAsn1xDef *defs,
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);
}
/* -----------------------------------------------------------------------------------
@@ -4225,7 +4335,6 @@ traverse_and_dump (GNode *node, gpointer unused)
guint i, depth;
GString *output;
gchar *string;
- Atlv *tlv;
Anode *an;
GList *l;
@@ -4233,18 +4342,17 @@ traverse_and_dump (GNode *node, gpointer unused)
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 (" ");
@@ -4416,9 +4524,9 @@ egg_asn1x_element_length (const guchar *data,
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;
@@ -4444,11 +4552,11 @@ egg_asn1x_element_content (const guchar *data,
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;
diff --git a/egg/egg-asn1x.h b/egg/egg-asn1x.h
index 036b9ce..bca01e0 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -58,6 +58,10 @@ typedef enum {
EGG_ASN1X_GENERALSTRING = 27
} EggAsn1xType;
+enum {
+ EGG_ASN1X_NO_STRICT = 0x01,
+} EggAsn1xFlags;
+
GNode* egg_asn1x_create (const EggAsn1xDef *defs,
const gchar *type);
@@ -68,6 +72,11 @@ GNode* egg_asn1x_create_and_decode (const EggAsn1xDef *defs,
const gchar *type,
GBytes *data);
+GNode* egg_asn1x_create_and_decode_full (const EggAsn1xDef *defs,
+ const gchar *type,
+ GBytes *data,
+ gint options);
+
void egg_asn1x_dump (GNode *asn);
void egg_asn1x_clear (GNode *asn);
@@ -75,13 +84,39 @@ void egg_asn1x_clear (GNode *asn);
gboolean egg_asn1x_decode (GNode *asn,
GBytes *data);
-gboolean egg_asn1x_decode_no_validate (GNode *asn,
- GBytes *data);
+gboolean egg_asn1x_decode_full (GNode *asn,
+ GBytes *data,
+ gint options);
+
+void egg_asn1x_set_any_from (GNode *node,
+ GNode *from);
+
+gboolean egg_asn1x_set_any_raw (GNode *node,
+ GBytes *raw);
+
+gboolean egg_asn1x_get_any_into (GNode *node,
+ GNode *into);
+
+gboolean egg_asn1x_get_any_into_full (GNode *node,
+ GNode *into,
+ gint options);
+
+GNode * egg_asn1x_get_any_as (GNode *node,
+ const EggAsn1xDef *defs,
+ const gchar *type);
+
+GNode * egg_asn1x_get_any_as_full (GNode *node,
+ const EggAsn1xDef *defs,
+ const gchar *type,
+ gint options);
+
+GBytes * egg_asn1x_get_any_raw (GNode *node,
+ EggAllocator allocator);
gboolean egg_asn1x_validate (GNode *asn,
gboolean strict);
-GBytes * egg_asn1x_encode (GNode *asn,
+GBytes * egg_asn1x_encode (GNode *asn,
EggAllocator allocator);
const gchar* egg_asn1x_message (GNode *asn);
@@ -107,23 +142,23 @@ gboolean egg_asn1x_set_choice (GNode *node,
gboolean egg_asn1x_get_boolean (GNode *node,
gboolean *value);
-gboolean egg_asn1x_set_boolean (GNode *node,
+void egg_asn1x_set_boolean (GNode *node,
gboolean value);
-gboolean egg_asn1x_set_null (GNode *node);
+void egg_asn1x_set_null (GNode *node);
GQuark egg_asn1x_get_enumerated (GNode *node);
-gboolean egg_asn1x_set_enumerated (GNode *node,
+void egg_asn1x_set_enumerated (GNode *node,
GQuark value);
gboolean egg_asn1x_get_integer_as_ulong (GNode *node,
gulong *value);
-gboolean egg_asn1x_set_integer_as_ulong (GNode *node,
+void egg_asn1x_set_integer_as_ulong (GNode *node,
gulong value);
-GBytes * egg_asn1x_get_integer_as_raw (GNode *node);
+GBytes * egg_asn1x_get_integer_as_raw (GNode *node);
void egg_asn1x_set_integer_as_raw (GNode *node,
GBytes *value);
@@ -131,7 +166,7 @@ void egg_asn1x_set_integer_as_raw (GNode *node,
void egg_asn1x_take_integer_as_raw (GNode *node,
GBytes *value);
-GBytes * egg_asn1x_get_integer_as_usg (GNode *node);
+GBytes * egg_asn1x_get_integer_as_usg (GNode *node);
void egg_asn1x_set_integer_as_usg (GNode *node,
GBytes *value);
@@ -139,25 +174,22 @@ void egg_asn1x_set_integer_as_usg (GNode *node,
void egg_asn1x_take_integer_as_usg (GNode *node,
GBytes *value);
-GBytes * egg_asn1x_get_raw_value (GNode *node);
+GBytes * egg_asn1x_get_value_raw (GNode *node);
-GBytes * egg_asn1x_get_element_raw (GNode *node);
-
-gboolean egg_asn1x_set_element_raw (GNode *node,
- GBytes *value);
+GBytes * egg_asn1x_get_element_raw (GNode *node);
guchar* egg_asn1x_get_string_as_raw (GNode *node,
EggAllocator allocator,
gsize *n_string);
-gboolean egg_asn1x_set_string_as_raw (GNode *node,
+void egg_asn1x_set_string_as_raw (GNode *node,
guchar *data,
gsize n_data,
GDestroyNotify destroy);
-GBytes * egg_asn1x_get_string_as_bytes (GNode *node);
+GBytes * egg_asn1x_get_string_as_bytes (GNode *node);
-GBytes * egg_asn1x_get_bits_as_raw (GNode *node,
+GBytes * egg_asn1x_get_bits_as_raw (GNode *node,
guint *n_bits);
void egg_asn1x_set_bits_as_raw (GNode *node,
@@ -172,7 +204,7 @@ gboolean egg_asn1x_get_bits_as_ulong (GNode *node,
gulong *value,
guint *n_bits);
-gboolean egg_asn1x_set_bits_as_ulong (GNode *node,
+void egg_asn1x_set_bits_as_ulong (GNode *node,
gulong value,
guint n_bits);
diff --git a/egg/egg-dn.c b/egg/egg-dn.c
index e3b092e..43bd772 100644
--- a/egg/egg-dn.c
+++ b/egg/egg-dn.c
@@ -52,7 +52,7 @@ dn_print_hex_value (GBytes *val)
static gchar*
dn_print_oid_value_parsed (GQuark oid,
guint flags,
- GBytes *val)
+ GNode *val)
{
GNode *asn1, *node;
GBytes *value;
@@ -65,7 +65,7 @@ dn_print_oid_value_parsed (GQuark oid,
asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
g_return_val_if_fail (asn1, NULL);
- if (!egg_asn1x_decode (asn1, val)) {
+ if (!egg_asn1x_get_any_into (val, asn1)) {
g_message ("couldn't decode value for OID: %s: %s",
g_quark_to_string (oid), egg_asn1x_message (asn1));
egg_asn1x_destroy (asn1);
@@ -81,7 +81,7 @@ dn_print_oid_value_parsed (GQuark oid,
else
node = asn1;
- value = egg_asn1x_get_raw_value (node);
+ value = egg_asn1x_get_value_raw (node);
data = g_bytes_get_data (value, &size);
/*
@@ -108,8 +108,9 @@ dn_print_oid_value_parsed (GQuark oid,
static gchar*
dn_print_oid_value (GQuark oid,
guint flags,
- GBytes *val)
+ GNode *val)
{
+ GBytes *der;
gchar *value;
g_assert (val != NULL);
@@ -120,7 +121,11 @@ dn_print_oid_value (GQuark oid,
return value;
}
- return dn_print_hex_value (val);
+ der = egg_asn1x_get_element_raw (val);
+ value = dn_print_hex_value (der);
+ g_bytes_unref (der);
+
+ return value;
}
static gchar*
@@ -129,7 +134,7 @@ dn_parse_rdn (GNode *asn)
const gchar *name;
guint flags;
GQuark oid;
- GBytes *value;
+ GNode *value;
gchar *display;
gchar *result;
@@ -141,7 +146,7 @@ dn_parse_rdn (GNode *asn)
flags = egg_oid_get_flags (oid);
name = egg_oid_get_name (oid);
- value = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "value", NULL));
+ value = egg_asn1x_node (asn, "value", NULL);
g_return_val_if_fail (value, NULL);
display = dn_print_oid_value (oid, flags, value);
@@ -149,7 +154,6 @@ dn_parse_rdn (GNode *asn)
"=", display, NULL);
g_free (display);
- g_bytes_unref (value);
return result;
}
@@ -200,11 +204,9 @@ egg_dn_read_part (GNode *asn, const gchar *match)
{
gboolean done = FALSE;
const gchar *name;
- GBytes *value;
GNode *node;
GQuark oid;
gint i, j;
- gchar *result;
g_return_val_if_fail (asn, NULL);
g_return_val_if_fail (match, NULL);
@@ -233,12 +235,7 @@ egg_dn_read_part (GNode *asn, const gchar *match)
node = egg_asn1x_node (asn, i, j, "value", NULL);
g_return_val_if_fail (node, NULL);
- value = egg_asn1x_get_element_raw (node);
- g_return_val_if_fail (value, NULL);
-
- result = dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
- g_bytes_unref (value);
- return result;
+ return dn_print_oid_value (oid, egg_oid_get_flags (oid), node);
}
}
@@ -250,7 +247,6 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
{
gboolean done = FALSE;
GNode *node;
- GBytes *value;
GQuark oid;
guint i, j;
@@ -279,12 +275,8 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
break;
}
- value = egg_asn1x_get_element_raw (node);
-
if (callback)
- (callback) (i, oid, value, user_data);
-
- g_bytes_unref (value);
+ (callback) (i, oid, node, user_data);
}
}
@@ -293,7 +285,7 @@ egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
gchar *
egg_dn_print_value (GQuark oid,
- GBytes *value)
+ GNode *value)
{
g_return_val_if_fail (oid != 0, NULL);
g_return_val_if_fail (value != NULL, NULL);
@@ -336,7 +328,6 @@ egg_dn_add_string_part (GNode *asn,
GQuark oid,
const gchar *string)
{
- GBytes *bytes;
GNode *node;
GNode *value;
GNode *val;
@@ -373,15 +364,6 @@ egg_dn_add_string_part (GNode *asn,
egg_asn1x_set_string_as_utf8 (val, g_strdup (string), g_free);
- bytes = egg_asn1x_encode (value, NULL);
- if (bytes == NULL) {
- g_warning ("couldn't build dn string value: %s", egg_asn1x_message (value));
- return;
- }
-
- if (!egg_asn1x_set_element_raw (egg_asn1x_node (node, "value", NULL), bytes))
- g_return_if_reached ();
-
+ egg_asn1x_set_any_from (egg_asn1x_node (node, "value", NULL), value);
egg_asn1x_destroy (value);
- g_bytes_unref (bytes);
}
diff --git a/egg/egg-dn.h b/egg/egg-dn.h
index a75e73d..bdf6b92 100644
--- a/egg/egg-dn.h
+++ b/egg/egg-dn.h
@@ -33,7 +33,7 @@ gchar* egg_dn_read_part (GNode *node,
typedef void (*EggDnCallback) (guint index,
GQuark oid,
- GBytes *value,
+ GNode *value,
gpointer user_data);
gboolean egg_dn_parse (GNode *node,
@@ -41,7 +41,7 @@ gboolean egg_dn_parse (GNode *node,
gpointer user_data);
gchar* egg_dn_print_value (GQuark oid,
- GBytes *value);
+ GNode *value);
void egg_dn_add_string_part (GNode *node,
GQuark oid,
diff --git a/egg/egg-symkey.c b/egg/egg-symkey.c
index d5459a5..54592d9 100644
--- a/egg/egg-symkey.c
+++ b/egg/egg-symkey.c
@@ -662,7 +662,7 @@ read_cipher_pkcs5_pbe (int cipher_algo,
int hash_algo,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_cipher_hd_t *cih)
{
GNode *asn = NULL;
@@ -689,10 +689,10 @@ read_cipher_pkcs5_pbe (int cipher_algo,
asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
g_return_val_if_fail (asn, FALSE);
- if (!egg_asn1x_decode (asn, data))
+ if (!egg_asn1x_get_any_into (data, asn))
goto done;
- salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
+ salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
if (!salt)
goto done;
if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
@@ -730,7 +730,7 @@ done:
}
static gboolean
-setup_pkcs5_rc2_params (GBytes *data,
+setup_pkcs5_rc2_params (GNode *any,
gcry_cipher_hd_t cih)
{
GNode *asn = NULL;
@@ -739,18 +739,16 @@ setup_pkcs5_rc2_params (GBytes *data,
gulong version;
gboolean ret = FALSE;
- g_assert (data);
+ g_assert (any != NULL);
- asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
- g_return_val_if_fail (asn, FALSE);
-
- if (!egg_asn1x_decode (asn, data))
+ asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
+ if (asn == NULL)
goto done;
if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "rc2ParameterVersion", NULL), &version))
goto done;
- iv = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "iv", NULL));
+ iv = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "iv", NULL));
if (!iv)
goto done;
@@ -770,7 +768,7 @@ done:
}
static gboolean
-setup_pkcs5_des_params (GBytes *data,
+setup_pkcs5_des_params (GNode *any,
gcry_cipher_hd_t cih)
{
GNode *asn = NULL;
@@ -778,15 +776,15 @@ setup_pkcs5_des_params (GBytes *data,
GBytes *iv;
gboolean ret;
- g_assert (data);
+ g_assert (any != NULL);
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params", data);
+ asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params");
if (!asn)
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data);
+ asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-CBC-params");
if (!asn)
return FALSE;
- iv = egg_asn1x_get_raw_value (asn);
+ iv = egg_asn1x_get_string_as_bytes (asn);
egg_asn1x_destroy (asn);
if (!iv)
@@ -807,7 +805,7 @@ setup_pkcs5_des_params (GBytes *data,
static gboolean
setup_pkcs5_pbkdf2_params (const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *any,
int cipher_algo,
gcry_cipher_hd_t cih)
{
@@ -820,17 +818,17 @@ setup_pkcs5_pbkdf2_params (const gchar *password,
gulong iterations;
g_assert (cipher_algo);
- g_assert (data != NULL);
+ g_assert (any != NULL);
ret = FALSE;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data);
+ asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-PBKDF2-params");
if (!asn)
goto done;
if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
iterations = 1;
- salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL));
+ salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", "specified", NULL));
if (!salt)
goto done;
@@ -861,13 +859,13 @@ done:
static gboolean
read_cipher_pkcs5_pbes2 (const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_cipher_hd_t *cih)
{
GNode *asn = NULL;
gboolean r, ret;
GQuark key_deriv_algo, enc_oid;
- GBytes *params = NULL;
+ GNode *params = NULL;
gcry_error_t gcry;
int algo, mode;
@@ -879,7 +877,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
*cih = NULL;
ret = FALSE;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data);
+ asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-5-PBES2-params");
if (!asn)
goto done;
@@ -910,7 +908,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
}
/* Read out the parameters */
- params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL));
+ params = egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL);
if (!params)
goto done;
@@ -941,8 +939,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password,
goto done;
}
- g_bytes_unref (params);
- params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL));
+ params = egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL);
if (!params)
goto done;
@@ -954,8 +951,6 @@ done:
*cih = NULL;
}
- if (params != NULL)
- g_bytes_unref (params);
egg_asn1x_destroy (asn);
return ret;
}
@@ -965,7 +960,7 @@ read_cipher_pkcs12_pbe (int cipher_algo,
int cipher_mode,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_cipher_hd_t *cih)
{
GNode *asn = NULL;
@@ -988,11 +983,11 @@ read_cipher_pkcs12_pbe (int cipher_algo,
if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
goto done;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data);
+ asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-PbeParams");
if (!asn)
goto done;
- salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL));
+ salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
if (!salt)
goto done;
if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
@@ -1037,7 +1032,7 @@ static gboolean
read_mac_pkcs12_pbe (int hash_algo,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_md_hd_t *mdh,
gsize *digest_len)
{
@@ -1060,14 +1055,17 @@ read_mac_pkcs12_pbe (int hash_algo,
if (gcry_md_algo_info (hash_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
goto done;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-MacData", data);
- if (!asn)
- goto done;
+ if (egg_asn1x_type (data) == EGG_ASN1X_ANY) {
+ asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-MacData");
+ if (!asn)
+ goto done;
+ data = asn;
+ }
- salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "macSalt", NULL));
+ salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (data, "macSalt", NULL));
if (!salt)
goto done;
- if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
+ if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (data, "iterations", NULL), &iterations))
goto done;
n_key = gcry_md_get_algo_dlen (hash_algo);
@@ -1107,7 +1105,7 @@ gboolean
egg_symkey_read_cipher (GQuark oid_scheme,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_cipher_hd_t *cih)
{
gboolean ret = FALSE;
@@ -1175,7 +1173,7 @@ gboolean
egg_symkey_read_mac (GQuark oid_scheme,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *data,
gcry_md_hd_t *mdh,
gsize *digest_len)
{
diff --git a/egg/egg-symkey.h b/egg/egg-symkey.h
index 8498613..f4938f6 100644
--- a/egg/egg-symkey.h
+++ b/egg/egg-symkey.h
@@ -77,13 +77,13 @@ gboolean egg_symkey_generate_pbkdf2 (int cipher_algo
gboolean egg_symkey_read_cipher (GQuark oid_scheme,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *params,
gcry_cipher_hd_t *cih);
gboolean egg_symkey_read_mac (GQuark oid_scheme,
const gchar *password,
gsize n_password,
- GBytes *data,
+ GNode *params,
gcry_md_hd_t *mdh,
gsize *digest_len);
diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am
index e736f85..0f47a06 100644
--- a/egg/tests/Makefile.am
+++ b/egg/tests/Makefile.am
@@ -22,6 +22,7 @@ LDADD = \
TEST_PROGS = \
test-asn1 \
+ test-asn1x \
test-dn \
test-decimal \
test-hex \
@@ -54,15 +55,3 @@ EXTRA_DIST = \
CLEANFILES = \
$(ASN_SRCS)
-
-# ------------------------------------------------------------------------------
-
-noinst_PROGRAMS = \
- test-asn1x
-
-test_asn1x_SOURCES = \
- test-asn1x.c
-
-test_asn1x_LDADD = \
- $(top_builddir)/egg/libegg-asn1x.la \
- $(LDADD)
diff --git a/egg/tests/files/test-personalname-1.der b/egg/tests/files/test-personalname-1.der
index 60d5d8c..13ba718 100644
--- a/egg/tests/files/test-personalname-1.der
+++ b/egg/tests/files/test-personalname-1.der
@@ -1 +1 @@
-1TurangaLeelaAlien
\ No newline at end of file
+1TurangaLeelaII
\ No newline at end of file
diff --git a/egg/tests/files/test-personalname-invalid.der b/egg/tests/files/test-personalname-invalid.der
new file mode 100644
index 0000000..60d5d8c
--- /dev/null
+++ b/egg/tests/files/test-personalname-invalid.der
@@ -0,0 +1 @@
+1TurangaLeelaAlien
\ No newline at end of file
diff --git a/egg/tests/files/test-pkcs12-2.der b/egg/tests/files/test-pkcs12-2.der
new file mode 100644
index 0000000..eff8c1e
Binary files /dev/null and b/egg/tests/files/test-pkcs12-2.der differ
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index 95667de..1313099 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -114,8 +114,7 @@ test_null (void)
g_assert_cmpint (EGG_ASN1X_NULL, ==, egg_asn1x_type (asn));
- if (!egg_asn1x_set_null (asn))
- g_assert_not_reached ();
+ egg_asn1x_set_null (asn);
data = egg_asn1x_encode (asn, g_realloc);
egg_assert_cmpmem (NULL_TEST, XL (NULL_TEST), ==, g_bytes_get_data (data, NULL), g_bytes_get_size (data));
@@ -187,8 +186,7 @@ test_unsigned (void)
egg_asn1x_clear (asn);
- if (!egg_asn1x_set_integer_as_ulong (asn, 253))
- g_assert_not_reached ();
+ egg_asn1x_set_integer_as_ulong (asn, 253);
check = egg_asn1x_encode (asn, NULL);
egg_assert_cmpmem (I253, XL (I253), ==, g_bytes_get_data (check, NULL), g_bytes_get_size (check));
@@ -533,9 +531,7 @@ test_bit_string_encode_decode_ulong (void)
asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
g_assert (asn);
- if (!egg_asn1x_set_bits_as_ulong (asn, bits, n_bits))
- g_assert_not_reached ();
-
+ egg_asn1x_set_bits_as_ulong (asn, bits, n_bits);
data = egg_asn1x_encode (asn, NULL);
g_assert (data);
@@ -584,10 +580,9 @@ test_have (void)
g_assert (!egg_asn1x_have (asn));
- if (!egg_asn1x_set_boolean (asn, TRUE))
- g_assert_not_reached ();
+ egg_asn1x_set_boolean (asn, TRUE);
- g_assert (!egg_asn1x_have (asn));
+ g_assert (egg_asn1x_have (asn));
data = egg_asn1x_encode (asn, NULL);
g_assert (data);
@@ -627,7 +622,7 @@ test_any_set_raw (void)
bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH),
test_is_freed, NULL);
- if (!egg_asn1x_set_element_raw (node, bytes))
+ if (!egg_asn1x_set_any_raw (node, bytes))
g_assert_not_reached ();
g_bytes_unref (bytes);
@@ -653,7 +648,6 @@ test_any_set_raw_explicit (void)
GBytes *bytes;
GNode *asn, *node;
GBytes *data;
- GBytes *check;
/* ENCODED SEQUENCE [89] ANY with OCTET STRING */
const gchar SEQ_ENCODING[] = "\x30\x0F\xBF\x59\x0C\x04\x0A""farnsworth";
@@ -666,7 +660,7 @@ test_any_set_raw_explicit (void)
g_assert (node);
bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
- if (!egg_asn1x_set_element_raw (node, bytes))
+ if (!egg_asn1x_set_any_raw (node, bytes))
g_assert_not_reached ();
g_bytes_unref (bytes);
@@ -675,13 +669,7 @@ test_any_set_raw_explicit (void)
egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING));
- check = egg_asn1x_get_element_raw (node);
- g_assert (check);
-
- egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH));
-
g_bytes_unref (data);
- g_bytes_unref (check);
egg_asn1x_destroy (asn);
g_assert (is_freed);
}
@@ -702,7 +690,7 @@ test_choice_not_chosen (void)
g_assert (node);
bytes = g_bytes_new_static (SFARNSWORTH, XL (SFARNSWORTH));
- if (!egg_asn1x_set_element_raw (node, bytes))
+ if (!egg_asn1x_set_any_raw (node, bytes))
g_assert_not_reached ();
g_bytes_unref (bytes);
@@ -736,7 +724,7 @@ perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsi
g_assert_not_reached ();
bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), test_is_freed, NULL);
- if (!egg_asn1x_set_element_raw (node, bytes))
+ if (!egg_asn1x_set_any_raw (node, bytes))
g_assert_not_reached ();
g_bytes_unref (bytes);
@@ -799,8 +787,7 @@ test_append (void)
g_assert (child);
/* Second integer is 2 */
- if (!egg_asn1x_set_integer_as_ulong (child, 2))
- g_assert_not_reached ();
+ egg_asn1x_set_integer_as_ulong (child, 2);
data = egg_asn1x_encode (asn, NULL);
g_assert (data != NULL);
@@ -822,12 +809,10 @@ test_append_and_clear (void)
g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
- if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 2))
- g_assert_not_reached ();
- if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 3))
- g_assert_not_reached ();
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 2);
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 3);
- g_assert_cmpuint (egg_asn1x_count (asn), ==, 0);
+ g_assert_cmpuint (egg_asn1x_count (asn), ==, 2);
data = egg_asn1x_encode (asn, NULL);
g_assert (data != NULL);
@@ -862,12 +847,10 @@ test_setof (void)
g_assert_cmpint (EGG_ASN1X_SET_OF, ==, egg_asn1x_type (asn));
/* Add integer 1, in SET OF DER should sort to front */
- if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 1))
- g_assert_not_reached ();
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 1);
/* Add integer 8, in SET OF DER should sort to back */
- if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 8))
- g_assert_not_reached ();
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_append (asn), 8);
data = egg_asn1x_encode (asn, NULL);
if (data == NULL) {
@@ -924,8 +907,7 @@ test_enumerated (void)
g_assert (value);
g_assert_cmpstr (g_quark_to_string (value), ==, "valueTwo");
- if (!egg_asn1x_set_enumerated (asn, g_quark_from_static_string ("valueThree")))
- g_assert_not_reached ();
+ egg_asn1x_set_enumerated (asn, g_quark_from_static_string ("valueThree"));
data = egg_asn1x_encode (asn, NULL);
g_assert (data != NULL);
@@ -984,14 +966,9 @@ test_asn1_integers (Test* test, gconstpointer unused)
asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
g_assert ("asn test structure is null" && asn != NULL);
- ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
- g_assert ("couldn't write integer" && ret);
-
- ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
- g_assert ("couldn't write integer" && ret);
-
- ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
- g_assert ("couldn't write integer" && ret);
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
+ egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
/* Now encode the whole caboodle */
data = egg_asn1x_encode (asn, NULL);
@@ -1027,6 +1004,10 @@ test_boolean_seq (Test* test, gconstpointer unused)
GNode *asn = NULL;
gboolean value, ret;
+ /* The first boolean has a default of FALSE, so doesn't get encoded if FALSE */
+ const gchar SEQ_BOOLEAN_TRUE_FALSE[] = "\x30\x06\x01\x01\xFF\x01\x01\x00";
+ const gchar SEQ_BOOLEAN_FALSE_FALSE[] = "\x30\x03\x01\x01\x00";
+
asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq");
g_assert ("asn test structure is null" && asn != NULL);
@@ -1036,22 +1017,23 @@ test_boolean_seq (Test* test, gconstpointer unused)
g_assert (ret == TRUE);
g_assert (value == FALSE);
- ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
- g_assert (ret == TRUE);
+ egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
+ egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean2", NULL), FALSE);
data = egg_asn1x_encode (asn, NULL);
g_assert (data != NULL);
+ egg_assert_cmpbytes (data, ==, SEQ_BOOLEAN_TRUE_FALSE, XL (SEQ_BOOLEAN_TRUE_FALSE));
+ g_bytes_unref (data);
ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
g_assert (ret);
g_assert (value == TRUE);
- ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
- g_assert (ret == TRUE);
+ egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
- g_bytes_unref (data);
data = egg_asn1x_encode (asn, NULL);
g_assert (data != NULL);
+ egg_assert_cmpbytes (data, ==, SEQ_BOOLEAN_FALSE_FALSE, XL (SEQ_BOOLEAN_FALSE_FALSE));
ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
g_assert (ret);
@@ -1072,8 +1054,7 @@ test_write_value (Test* test, gconstpointer unused)
asn = egg_asn1x_create (test_asn1_tab, "TestData");
g_assert ("asn test structure is null" && asn != NULL);
- if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
- g_assert_not_reached ();
+ egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
encoded = egg_asn1x_encode (asn, NULL);
g_assert (encoded);
@@ -1100,8 +1081,7 @@ test_element_length_content (Test* test, gconstpointer unused)
asn = egg_asn1x_create (test_asn1_tab, "TestData");
g_assert ("asn test structure is null" && asn != NULL);
- if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
- g_assert_not_reached ();
+ egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
buffer = egg_asn1x_encode (asn, NULL);
g_assert (buffer != NULL);
@@ -1143,19 +1123,22 @@ test_read_element (Test* test, gconstpointer unused)
asn = egg_asn1x_create (test_asn1_tab, "TestData");
g_assert ("asn test structure is null" && asn != NULL);
- if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
- g_assert_not_reached ();
+ egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL);
buffer = egg_asn1x_encode (asn, NULL);
g_assert (buffer != NULL);
+ /* Have to decode before we can get raw elements */
+ if (!egg_asn1x_decode (asn, buffer))
+ g_assert_not_reached ();
+
/* Now the real test */
data = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "data", NULL));
g_assert (data != NULL);
g_assert_cmpint (g_bytes_get_size (data), ==, 11);
g_bytes_unref (data);
- data = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "data", NULL));
+ data = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "data", NULL));
g_assert (data != NULL);
egg_assert_cmpbytes (data, ==, "SOME DATA", 9);
g_bytes_unref (data);
diff --git a/egg/tests/test-asn1x.c b/egg/tests/test-asn1x.c
index 4581756..ad75e62 100644
--- a/egg/tests/test-asn1x.c
+++ b/egg/tests/test-asn1x.c
@@ -32,6 +32,7 @@
#include <unistd.h>
#if 0
+#include <libtasn1.h>
static void
build_personal_name (void)
{
@@ -39,7 +40,7 @@ build_personal_name (void)
guchar buffer[10024];
int res, len;
- res = asn1_array2tree (pkix_asn1_tab, &asn1_pkix, NULL);
+ res = asn1_array2tree ((ASN1_ARRAY_TYPE*)pkix_asn1_tab, &asn1_pkix, NULL);
g_assert (res == ASN1_SUCCESS);
res = asn1_create_element (asn1_pkix, "PKIX1.PersonalName", &asn);
@@ -48,7 +49,7 @@ build_personal_name (void)
asn1_write_value (asn, "surname", "Turanga", 7);
asn1_write_value (asn, "given-name", "Leela", 5);
asn1_write_value (asn, "initials", NULL, 0);
- asn1_write_value (asn, "generation-qualifier", "Alien", 5);
+ asn1_write_value (asn, "generation-qualifier", "II", 2);
len = sizeof (buffer);
res = asn1_der_coding (asn, "", buffer, &len, NULL);
@@ -63,55 +64,136 @@ build_personal_name (void)
}
#endif
+typedef struct {
+ GBytes *data;
+} Test;
+
+typedef struct {
+ const EggAsn1xDef *defs;
+ const gchar *filename;
+ const gchar *identifier;
+} Fixture;
+
+static const Fixture parse_test_fixtures[] = {
+ { pkix_asn1_tab, SRCDIR "/files/test-certificate-1.der", "Certificate" },
+ { pkix_asn1_tab, SRCDIR "/files/test-pkcs8-1.der", "pkcs-8-PrivateKeyInfo" },
+ { pk_asn1_tab, SRCDIR "/files/test-rsakey-1.der", "RSAPrivateKey" },
+ { pkix_asn1_tab, SRCDIR "/files/test-personalname-1.der", "PersonalName" },
+ { pkix_asn1_tab, SRCDIR "/files/test-pkcs7-1.der", "pkcs-7-ContentInfo" },
+ { pkix_asn1_tab, SRCDIR "/files/test-pkcs7-2.der", "pkcs-7-ContentInfo" },
+};
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ const gchar *filename = data;
+ GError *error = NULL;
+ gchar *contents;
+ gsize length;
+
+ g_file_get_contents (filename, (gchar**)&contents, &length, &error);
+ g_assert_no_error (error);
+
+ test->data = g_bytes_new_take (contents, length);
+}
+
+static void
+setup_parsing (Test *test,
+ gconstpointer data)
+{
+ const Fixture *fixture = data;
+ setup (test, fixture->filename);
+}
+
static void
-test_some_asn1_stuff (const EggAsn1xDef *defs,
- const gchar *file,
- const gchar *identifier)
+teardown (Test *test,
+ gconstpointer unused)
{
+ g_bytes_unref (test->data);
+}
+
+static void
+test_decode_encode (Test *test,
+ gconstpointer data)
+{
+ const Fixture *fixture = data;
GNode *asn;
GBytes *encoded;
- gpointer data;
- gsize n_data;
- GBytes *bytes;
- if (!g_file_get_contents (file, (gchar**)&data, &n_data, NULL))
- g_assert_not_reached ();
- bytes = g_bytes_new_take (data, n_data);
- asn = egg_asn1x_create (defs, identifier);
- egg_asn1x_dump (asn);
+ asn = egg_asn1x_create (fixture->defs, fixture->identifier);
- if (!egg_asn1x_decode (asn, bytes))
- g_warning ("decode of %s failed: %s", identifier, egg_asn1x_message (asn));
+ if (g_test_verbose ())
+ egg_asn1x_dump (asn);
+
+ if (!egg_asn1x_decode (asn, test->data)) {
+ g_warning ("decode of %s failed: %s", fixture->identifier,
+ egg_asn1x_message (asn));
+ g_assert_not_reached ();
+ }
encoded = egg_asn1x_encode (asn, NULL);
- if (encoded == NULL)
- g_warning ("encode of %s failed: %s", identifier, egg_asn1x_message (asn));
+ if (encoded == NULL) {
+ g_warning ("encode of %s failed: %s", fixture->identifier,
+ egg_asn1x_message (asn));
+ g_assert_not_reached ();
+ }
/* Decode the encoding */
- if (!egg_asn1x_decode (asn, encoded))
- g_warning ("decode of encoded %s failed: %s", identifier, egg_asn1x_message (asn));
+ if (!egg_asn1x_decode (asn, encoded)) {
+ g_warning ("decode of encoded %s failed: %s", fixture->identifier,
+ egg_asn1x_message (asn));
+ g_assert_not_reached ();
+ }
egg_asn1x_clear (asn);
egg_asn1x_destroy (asn);
- g_bytes_unref (bytes);
g_bytes_unref (encoded);
}
+static void
+test_pkcs12_decode (Test *test,
+ gconstpointer unused)
+{
+ GNode *asn;
+
+ asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PFX");
+
+ if (g_test_verbose ())
+ egg_asn1x_dump (asn);
+
+ if (!egg_asn1x_decode (asn, test->data)) {
+ g_warning ("decode of indefinite pkcs-12-PFX failed: %s",
+ egg_asn1x_message (asn));
+ g_assert_not_reached ();
+ }
+
+ egg_asn1x_destroy (asn);
+}
+
int
main (int argc, char **argv)
{
- /* Build up a personal name, which is a set */
+ gchar *name;
+ gint i;
+
+ g_test_init (&argc, &argv, NULL);
+
#if 0
+ /* Build up a personal name, which is a set */
build_personal_name ();
#endif
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-certificate-1.der", "Certificate");
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs8-1.der", "pkcs-8-PrivateKeyInfo");
- test_some_asn1_stuff (pk_asn1_tab, SRCDIR "/files/test-rsakey-1.der", "RSAPrivateKey");
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-personalname-1.der", "PersonalName");
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs7-1.der", "pkcs-7-ContentInfo");
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs7-2.der", "pkcs-7-ContentInfo");
- test_some_asn1_stuff (pkix_asn1_tab, SRCDIR "/files/test-pkcs12-1.der", "pkcs-12-PFX");
+ for (i = 0; i < G_N_ELEMENTS (parse_test_fixtures); i++) {
+ name = g_strdup_printf ("/asn1x/encode-decode-%s", parse_test_fixtures[i].identifier);
+ g_test_add (name, Test, &parse_test_fixtures[i], setup_parsing, test_decode_encode, teardown);
+ g_free (name);
+ }
+
+ g_test_add ("/asn1x/pkcs12-decode/1", Test, SRCDIR "/files/test-pkcs12-1.der",
+ setup, test_pkcs12_decode, teardown);
+ g_test_add ("/asn1x/pkcs12-decode/2", Test, SRCDIR "/files/test-pkcs12-2.der",
+ setup, test_pkcs12_decode, teardown);
- return 0;
+ return g_test_run ();
}
diff --git a/egg/tests/test-dn.c b/egg/tests/test-dn.c
index cf83dcb..6494679 100644
--- a/egg/tests/test-dn.c
+++ b/egg/tests/test-dn.c
@@ -85,24 +85,30 @@ test_dn_value (Test* test, gconstpointer unused)
const guchar value[] = { 0x13, 0x1a, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x43, 0x41 };
gsize n_value = 28;
GBytes *bytes;
+ GNode *asn;
GQuark oid;
gchar *text;
+ bytes = g_bytes_new_static (value, n_value);
+
+ asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "AttributeValue", bytes);
+ g_assert (asn != NULL);
+
/* Some printable strings */
oid = g_quark_from_static_string ("2.5.4.3");
- bytes = g_bytes_new_static (value, n_value);
- text = egg_dn_print_value (oid, bytes);
- g_bytes_unref (bytes);
+ text = egg_dn_print_value (oid, asn);
g_assert_cmpstr (text, ==, "Thawte Personal Premium CA");
g_free (text);
/* Unknown oid */
oid = g_quark_from_static_string ("1.1.1.1.1.1");
bytes = g_bytes_new_static (value, n_value);
- text = egg_dn_print_value (oid, bytes);
- g_bytes_unref (bytes);
+ text = egg_dn_print_value (oid, asn);
g_assert_cmpstr (text, ==, "#131A54686177746520506572736F6E616C205072656D69756D204341");
g_free (text);
+
+ egg_asn1x_destroy (asn);
+ g_bytes_unref (bytes);
}
static int last_index = 0;
@@ -110,7 +116,7 @@ static int last_index = 0;
static void
concatenate_dn (guint index,
GQuark oid,
- GBytes *value,
+ GNode *value,
gpointer user_data)
{
GString *dn = user_data;
@@ -118,7 +124,6 @@ concatenate_dn (guint index,
g_assert (oid);
g_assert (value != NULL);
- g_assert (g_bytes_get_size (value) != 0);
g_assert (index == last_index);
++last_index;
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index 5412a63..0465328 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -33,7 +33,8 @@ TestData ::= SEQUENCE {
}
TestBooleanSeq ::= SEQUENCE {
- boolean BOOLEAN DEFAULT FALSE
+ boolean BOOLEAN DEFAULT FALSE,
+ boolean2 BOOLEAN
}
TestOid ::= SEQUENCE {
diff --git a/gcr/gcr-certificate-extensions.c b/gcr/gcr-certificate-extensions.c
index ba16907..6b8033c 100644
--- a/gcr/gcr-certificate-extensions.c
+++ b/gcr/gcr-certificate-extensions.c
@@ -56,7 +56,7 @@ _gcr_certificate_extension_find (GNode *cert,
}
/* Extension value */
- return egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
+ return egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
}
}
@@ -172,28 +172,28 @@ general_name_parse_other (GNode *node, GcrGeneralName *general)
{
GNode *decode = NULL;
GQuark oid;
- GBytes *value;
+ GNode *any;
general->type = GCR_GENERAL_NAME_OTHER;
general->description = _("Other Name");
+ general->display = NULL;
oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL));
- value = egg_asn1x_get_element_raw (egg_asn1x_node (node, "value", NULL));
+ any = egg_asn1x_node (node, "value", NULL);
- if (value == NULL)
+ if (any == NULL)
return;
if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) {
general->description = _("XMPP Addr");
- decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "UTF8String", value);
+ decode = egg_asn1x_get_any_as (any, pkix_asn1_tab, "UTF8String");
general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
} else if (oid == GCR_OID_ALT_NAME_DNS_SRV) {
general->description = _("DNS SRV");
- decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "IA5String", value);
+ decode = egg_asn1x_get_any_as (any, pkix_asn1_tab, "IA5String");
general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
}
- g_bytes_unref (value);
egg_asn1x_destroy (decode);
}
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index 631267c..d4e05f4 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -789,7 +789,7 @@ typedef struct {
static void
on_parsed_dn_part (guint index,
GQuark oid,
- GBytes *value,
+ GNode *value,
gpointer user_data)
{
GcrRenderer *renderer = ((AppendDnClosure *)user_data)->renderer;
@@ -935,7 +935,7 @@ _gcr_certificate_renderer_append_extension (GcrRenderer *renderer,
g_return_if_fail (oid);
/* Extension value */
- value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL));
+ value = egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
/* The custom parsers */
if (oid == GCR_OID_BASIC_CONSTRAINTS)
diff --git a/gcr/gcr-certificate-request.c b/gcr/gcr-certificate-request.c
index 81a510a..686ed06 100644
--- a/gcr/gcr-certificate-request.c
+++ b/gcr/gcr-certificate-request.c
@@ -420,7 +420,7 @@ prepare_subject_public_key_and_mechanisms (GcrCertificateRequest *self,
}
node = egg_asn1x_node (self->asn, "certificationRequestInfo", "subjectPKInfo", NULL);
- if (!egg_asn1x_set_element_raw (node, encoded))
+ if (!egg_asn1x_decode (node, encoded))
g_return_val_if_reached (FALSE);
g_bytes_unref (encoded);
@@ -434,7 +434,6 @@ encode_take_signature_into_request (GcrCertificateRequest *self,
guchar *result,
gsize n_result)
{
- GBytes *data;
GNode *params;
GNode *node;
@@ -446,9 +445,7 @@ encode_take_signature_into_request (GcrCertificateRequest *self,
node = egg_asn1x_node (self->asn, "signatureAlgorithm", "parameters", NULL);
params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
- data = egg_asn1x_encode (params, NULL);
- egg_asn1x_set_element_raw (node, data);
- g_bytes_unref (data);
+ egg_asn1x_set_any_from (node, params);
}
/**
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 0dc32b7..b617a24 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -566,7 +566,7 @@ done:
static gint
parse_der_private_key_dsa_parts (GcrParser *self,
GBytes *keydata,
- GBytes *params)
+ GNode *params)
{
gint ret = GCR_ERROR_UNRECOGNIZED;
GNode *asn_params = NULL;
@@ -575,7 +575,7 @@ parse_der_private_key_dsa_parts (GcrParser *self,
parsed = push_parsed (self, TRUE);
- asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+ asn_params = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata);
if (!asn_params || !asn_key)
goto done;
@@ -629,7 +629,7 @@ static gint
handle_subject_public_key_rsa (GcrParser *self,
GcrParsed *parsed,
GBytes *key,
- GBytes *params)
+ GNode *params)
{
gint res = GCR_ERROR_FAILURE;
GNode *asn = NULL;
@@ -656,14 +656,14 @@ static gint
handle_subject_public_key_dsa (GcrParser *self,
GcrParsed *parsed,
GBytes *key,
- GBytes *params)
+ GNode *params)
{
gint res = GCR_ERROR_FAILURE;
GNode *key_asn = NULL;
GNode *param_asn = NULL;
key_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", key);
- param_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+ param_asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
if (!key_asn || !param_asn)
goto done;
@@ -690,7 +690,7 @@ parse_der_subject_public_key (GcrParser *self,
GBytes *data)
{
GcrParsed *parsed;
- GBytes *params;
+ GNode *params;
GBytes *key;
GNode *asn = NULL;
GNode *node;
@@ -708,8 +708,7 @@ parse_der_subject_public_key (GcrParser *self,
node = egg_asn1x_node (asn, "algorithm", "algorithm", NULL);
oid = egg_asn1x_get_oid_as_quark (node);
- node = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
- params = egg_asn1x_get_element_raw (node);
+ params = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
node = egg_asn1x_node (asn, "subjectPublicKey", NULL);
key = egg_asn1x_get_bits_as_raw (node, &bits);
@@ -724,7 +723,6 @@ parse_der_subject_public_key (GcrParser *self,
ret = GCR_ERROR_UNRECOGNIZED;
g_bytes_unref (key);
- g_bytes_unref (params);
if (ret == SUCCESS)
parsed_fire (self, parsed);
@@ -747,7 +745,7 @@ parse_der_pkcs8_plain (GcrParser *self,
CK_KEY_TYPE key_type;
GQuark key_algo;
GBytes *keydata = NULL;
- GBytes *params = NULL;
+ GNode *params = NULL;
GNode *asn = NULL;
GcrParsed *parsed;
@@ -775,11 +773,11 @@ parse_der_pkcs8_plain (GcrParser *self,
goto done;
}
- keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL));
+ keydata = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL));
if (!keydata)
goto done;
- params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL));
+ params = egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL);
ret = SUCCESS;
@@ -809,8 +807,6 @@ done:
if (keydata)
g_bytes_unref (keydata);
- if (params)
- g_bytes_unref (params);
egg_asn1x_destroy (asn);
pop_parsed (self, parsed);
return ret;
@@ -827,7 +823,7 @@ parse_der_pkcs8_encrypted (GcrParser *self,
gint ret, r;
GQuark scheme;
guchar *crypted = NULL;
- GBytes *params = NULL;
+ GNode *params = NULL;
GBytes *cbytes;
gsize n_crypted;
const gchar *password;
@@ -849,7 +845,7 @@ parse_der_pkcs8_encrypted (GcrParser *self,
if (!scheme)
goto done;
- params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL));
+ params = egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL);
/* Loop to try different passwords */
for (;;) {
@@ -901,8 +897,6 @@ parse_der_pkcs8_encrypted (GcrParser *self,
}
done:
- if (params)
- g_bytes_unref (params);
if (cih)
gcry_cipher_close (cih);
egg_asn1x_destroy (asn);
@@ -977,7 +971,7 @@ parse_der_certificate (GcrParser *self,
static gint
handle_pkcs7_signed_data (GcrParser *self,
- GBytes *data)
+ GNode *content)
{
GNode *asn = NULL;
GNode *node;
@@ -987,7 +981,7 @@ handle_pkcs7_signed_data (GcrParser *self,
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data);
+ asn = egg_asn1x_get_any_as (content, pkix_asn1_tab, "pkcs-7-SignedData");
if (!asn)
goto done;
@@ -1023,7 +1017,7 @@ parse_der_pkcs7 (GcrParser *self,
GNode *asn = NULL;
GNode *node;
gint ret;
- GBytes *content = NULL;
+ GNode *content = NULL;
GQuark oid;
GcrParsed *parsed;
@@ -1050,15 +1044,13 @@ parse_der_pkcs7 (GcrParser *self,
goto done;
}
- content = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "content", NULL));
+ content = egg_asn1x_node (asn, "content", NULL);
if (!content)
goto done;
ret = handle_pkcs7_signed_data (self, content);
done:
- if (content)
- g_bytes_unref (content);
egg_asn1x_destroy (asn);
pop_parsed (self, parsed);
return ret;
@@ -1068,37 +1060,6 @@ done:
* PKCS12
*/
-static GNode *
-decode_pkcs12_asn1_accepting_invalid_crap (const EggAsn1xDef *defs,
- const gchar *identifier,
- GBytes *data)
-{
- GNode *asn;
-
- /*
- * Because PKCS#12 files, the bags specifically, are notorious for
- * being crappily constructed and are often break rules such as DER
- * sorting order etc.. we parse the DER in a non-strict fashion.
- *
- * The rules in DER are designed for X.509 certificates, so there is
- * only one way to represent a given certificate (although they fail
- * at that as well). But with PKCS#12 we don't have such high
- * requirements, and we can slack off on our validation.
- */
-
- asn = egg_asn1x_create (defs, identifier);
- g_return_val_if_fail (asn != NULL, NULL);
-
- /* Passing FALSE as the strictness argument */
- if (!egg_asn1x_decode_no_validate (asn, data) ||
- !egg_asn1x_validate (asn, FALSE)) {
- egg_asn1x_destroy (asn);
- asn = NULL;
- }
-
- return asn;
-}
-
static gint
handle_pkcs12_cert_bag (GcrParser *self,
GBytes *data)
@@ -1106,25 +1067,24 @@ handle_pkcs12_cert_bag (GcrParser *self,
GNode *asn = NULL;
GNode *asn_content = NULL;
guchar *certificate = NULL;
- GBytes *element = NULL;
+ GNode *element = NULL;
gsize n_certificate;
GBytes *bytes;
gint ret;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-CertBag",
- data);
+ asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-CertBag",
+ data, EGG_ASN1X_NO_STRICT);
if (!asn)
goto done;
ret = GCR_ERROR_FAILURE;
- element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "certValue", NULL));
+ element = egg_asn1x_node (asn, "certValue", NULL);
if (!element)
goto done;
- asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element);
+ asn_content = egg_asn1x_get_any_as (element, pkix_asn1_tab, "pkcs-7-Data");
if (!asn_content)
goto done;
@@ -1137,8 +1097,6 @@ handle_pkcs12_cert_bag (GcrParser *self,
g_bytes_unref (bytes);
done:
- if (element)
- g_bytes_unref (element);
egg_asn1x_destroy (asn_content);
egg_asn1x_destroy (asn);
return ret;
@@ -1150,7 +1108,6 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
guint count, i;
GQuark oid;
GNode *node;
- GBytes *element;
GNode *asn_str;
gchar *result;
@@ -1163,10 +1120,7 @@ parse_pkcs12_bag_friendly_name (GNode *asn)
if (oid == GCR_OID_PKCS9_ATTRIBUTE_FRIENDLY) {
node = egg_asn1x_node (asn, i, "values", 1, NULL);
if (node != NULL) {
- element = egg_asn1x_get_element_raw (node);
- asn_str = egg_asn1x_create_and_decode (pkix_asn1_tab, "BMPString",
- element);
- g_bytes_unref (element);
+ asn_str = egg_asn1x_get_any_as (node, pkix_asn1_tab, "BMPString");
if (asn_str) {
result = egg_asn1x_get_bmpstring_as_utf8 (asn_str);
egg_asn1x_destroy (asn_str);
@@ -1187,6 +1141,7 @@ handle_pkcs12_bag (GcrParser *self,
gint ret, r;
guint count = 0;
GQuark oid;
+ GNode *value;
GBytes *element = NULL;
gchar *friendly;
guint i;
@@ -1194,9 +1149,8 @@ handle_pkcs12_bag (GcrParser *self,
ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-SafeContents",
- data);
+ asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-SafeContents",
+ data, EGG_ASN1X_NO_STRICT);
if (!asn)
goto done;
@@ -1215,10 +1169,11 @@ handle_pkcs12_bag (GcrParser *self,
if (!oid)
goto done;
- element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, i, "bagValue", NULL));
- if (!element)
+ value = egg_asn1x_node (asn, i, "bagValue", NULL);
+ if (!value)
goto done;
+ element = egg_asn1x_get_element_raw (value);
parsed = push_parsed (self, FALSE);
friendly = parse_pkcs12_bag_friendly_name (egg_asn1x_node (asn, i, "bagAttributes", NULL));
@@ -1266,14 +1221,14 @@ done:
static gint
handle_pkcs12_encrypted_bag (GcrParser *self,
- GBytes *data)
+ GNode *bag)
{
PasswordState pstate = PASSWORD_STATE_INIT;
GNode *asn = NULL;
gcry_cipher_hd_t cih = NULL;
gcry_error_t gcry;
guchar *crypted = NULL;
- GBytes *params = NULL;
+ GNode *params = NULL;
gsize n_crypted;
const gchar *password;
GBytes *cbytes;
@@ -1283,9 +1238,8 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-7-EncryptedData",
- data);
+ asn = egg_asn1x_get_any_as_full (bag, pkix_asn1_tab, "pkcs-7-EncryptedData",
+ EGG_ASN1X_NO_STRICT);
if (!asn)
goto done;
@@ -1296,7 +1250,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
if (!scheme)
goto done;
- params = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL));
+ params = egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL);
if (!params)
goto done;
@@ -1352,8 +1306,6 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
}
done:
- if (params)
- g_bytes_unref (params);
if (cih)
gcry_cipher_close (cih);
egg_asn1x_destroy (asn);
@@ -1368,7 +1320,7 @@ handle_pkcs12_safe (GcrParser *self,
GNode *asn = NULL;
GNode *asn_content = NULL;
gint ret, r;
- GBytes *bag = NULL;
+ GNode *bag;
GBytes *content;
GQuark oid;
guint i;
@@ -1376,9 +1328,8 @@ handle_pkcs12_safe (GcrParser *self,
ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-AuthenticatedSafe",
- data);
+ asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-AuthenticatedSafe",
+ data, EGG_ASN1X_NO_STRICT);
if (!asn)
goto done;
@@ -1396,20 +1347,16 @@ handle_pkcs12_safe (GcrParser *self,
oid = egg_asn1x_get_oid_as_quark (node);
- node = egg_asn1x_node (asn, i + 1, "content", NULL);
- if (!node)
+ bag = egg_asn1x_node (asn, i + 1, "content", NULL);
+ if (!bag)
goto done;
- bag = egg_asn1x_get_element_raw (node);
- g_return_val_if_fail (bag != NULL, ret);
-
/* A non encrypted bag, just parse */
if (oid == GCR_OID_PKCS7_DATA) {
egg_asn1x_destroy (asn_content);
- asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-7-Data",
- bag);
+ asn_content = egg_asn1x_get_any_as_full (bag, pkix_asn1_tab,
+ "pkcs-7-Data", EGG_ASN1X_NO_STRICT);
if (!asn_content)
goto done;
@@ -1430,9 +1377,6 @@ handle_pkcs12_safe (GcrParser *self,
r = GCR_ERROR_UNRECOGNIZED;
}
- g_bytes_unref (bag);
- bag = NULL;
-
if (r == GCR_ERROR_FAILURE ||
r == GCR_ERROR_CANCELLED ||
r == GCR_ERROR_LOCKED) {
@@ -1444,8 +1388,6 @@ handle_pkcs12_safe (GcrParser *self,
ret = SUCCESS;
done:
- if (bag != NULL)
- g_bytes_unref (bag);
egg_asn1x_destroy (asn);
egg_asn1x_destroy (asn_content);
return ret;
@@ -1465,7 +1407,6 @@ verify_pkcs12_safe (GcrParser *self,
gsize n_digest;
GQuark algorithm;
GNode *mac_data;
- GBytes *params = NULL;
int ret, r;
ret = GCR_ERROR_FAILURE;
@@ -1484,10 +1425,6 @@ verify_pkcs12_safe (GcrParser *self,
if (!algorithm)
goto done;
- params = egg_asn1x_get_element_raw (mac_data);
- if (!params)
- goto done;
-
digest = egg_asn1x_get_string_as_raw (egg_asn1x_node (mac_data, "mac", "digest", NULL), NULL, &n_digest);
if (!digest)
goto done;
@@ -1503,7 +1440,7 @@ verify_pkcs12_safe (GcrParser *self,
}
/* Parse the encryption stuff into a cipher. */
- if (!egg_symkey_read_mac (algorithm, password, -1, params, &mdh, &mac_len)) {
+ if (!egg_symkey_read_mac (algorithm, password, -1, mac_data, &mdh, &mac_len)) {
ret = GCR_ERROR_FAILURE;
goto done;
}
@@ -1529,8 +1466,6 @@ verify_pkcs12_safe (GcrParser *self,
}
done:
- if (params)
- g_bytes_unref (params);
if (mdh)
gcry_md_close (mdh);
g_free (digest);
@@ -1543,17 +1478,28 @@ parse_der_pkcs12 (GcrParser *self,
GBytes *data)
{
GNode *asn = NULL;
- GNode *asn_content = NULL;
gint ret;
- GBytes *element = NULL;
- GBytes *content = NULL;
+ GNode *content = NULL;
+ GBytes *string = NULL;
GQuark oid;
GcrParsed *parsed;
parsed = push_parsed (self, FALSE);
ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX", data);
+ /*
+ * Because PKCS#12 files, the bags specifically, are notorious for
+ * being crappily constructed and are often break rules such as DER
+ * sorting order etc.. we parse the DER in a non-strict fashion.
+ *
+ * The rules in DER are designed for X.509 certificates, so there is
+ * only one way to represent a given certificate (although they fail
+ * at that as well). But with PKCS#12 we don't have such high
+ * requirements, and we can slack off on our validation.
+ */
+
+ asn = egg_asn1x_create_and_decode_full (pkix_asn1_tab, "pkcs-12-PFX",
+ data, EGG_ASN1X_NO_STRICT);
if (!asn)
goto done;
@@ -1569,28 +1515,24 @@ parse_der_pkcs12 (GcrParser *self,
goto done;
}
- element = egg_asn1x_get_element_raw (egg_asn1x_node (asn, "authSafe", "content", NULL));
- if (!element)
- goto done;
-
- asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data", element);
- if (!asn_content)
+ content = egg_asn1x_get_any_as (egg_asn1x_node (asn, "authSafe", "content", NULL),
+ pkix_asn1_tab, "pkcs-7-Data");
+ if (!content)
goto done;
- content = egg_asn1x_get_string_as_bytes (asn_content);
- if (!content)
+ string = egg_asn1x_get_string_as_bytes (content);
+ if (!string)
goto done;
- ret = verify_pkcs12_safe (self, asn, content);
+ ret = verify_pkcs12_safe (self, asn, string);
if (ret == SUCCESS)
- ret = handle_pkcs12_safe (self, content);
+ ret = handle_pkcs12_safe (self, string);
done:
- if (element)
- g_bytes_unref (element);
if (content)
- g_bytes_unref (content);
- egg_asn1x_destroy (asn_content);
+ egg_asn1x_destroy (content);
+ if (string)
+ g_bytes_unref (string);
egg_asn1x_destroy (asn);
pop_parsed (self, parsed);
return ret;
diff --git a/gcr/gcr-subject-public-key.c b/gcr/gcr-subject-public-key.c
index f41b127..46c8d42 100644
--- a/gcr/gcr-subject-public-key.c
+++ b/gcr/gcr-subject-public-key.c
@@ -528,7 +528,6 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs,
GNode *key_asn;
GNode *params_asn;
GBytes *key;
- GBytes *params;
GBytes *usg;
_gcr_oids_init ();
@@ -562,17 +561,14 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs,
egg_asn1x_set_null (params_asn);
- params = egg_asn1x_encode (params_asn, g_realloc);
- egg_asn1x_destroy (params_asn);
-
egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
key, g_bytes_get_size (key) * 8);
egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
- egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+ egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
+ egg_asn1x_destroy (params_asn);
g_bytes_unref (key);
- g_bytes_unref (params);
return TRUE;
}
@@ -627,7 +623,6 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
const GckAttribute *value, *g, *q, *p;
GNode *key_asn, *params_asn;
GBytes *key;
- GBytes *params;
_gcr_oids_init ();
@@ -680,17 +675,14 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs,
key = egg_asn1x_encode (key_asn, NULL);
egg_asn1x_destroy (key_asn);
- params = egg_asn1x_encode (params_asn, NULL);
- egg_asn1x_destroy (params_asn);
-
egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
key, g_bytes_get_size (key) * 8);
- egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+ egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
g_bytes_unref (key);
- g_bytes_unref (params);
+ egg_asn1x_destroy (params_asn);
return TRUE;
}
@@ -785,7 +777,7 @@ calculate_rsa_key_size (GBytes *data)
asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
g_return_val_if_fail (asn, 0);
- content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL));
+ content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "modulus", NULL));
if (!content)
g_return_val_if_reached (0);
@@ -799,16 +791,16 @@ calculate_rsa_key_size (GBytes *data)
}
static guint
-calculate_dsa_params_size (GBytes *data)
+calculate_dsa_params_size (GNode *params)
{
GNode *asn;
GBytes *content;
guint key_size;
- asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
+ asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
g_return_val_if_fail (asn, 0);
- content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL));
+ content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "p", NULL));
if (!content)
g_return_val_if_reached (0);
@@ -825,6 +817,7 @@ guint
_gcr_subject_public_key_calculate_size (GNode *subject_public_key)
{
GBytes *key;
+ GNode *params;
guint key_size = 0;
guint n_bits;
GQuark oid;
@@ -843,9 +836,8 @@ _gcr_subject_public_key_calculate_size (GNode *subject_public_key)
/* The DSA key size is discovered by the prime in params */
} else if (oid == GCR_OID_PKIX1_DSA) {
- key = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL));
- key_size = calculate_dsa_params_size (key);
- g_bytes_unref (key);
+ params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
+ key_size = calculate_dsa_params_size (params);
} else {
g_message ("unsupported key algorithm: %s", g_quark_to_string (oid));
diff --git a/gcr/tests/files/usr0052-firefox.p12 b/gcr/tests/files/usr0052-firefox.p12
new file mode 100644
index 0000000..eff8c1e
Binary files /dev/null and b/gcr/tests/files/usr0052-firefox.p12 differ
diff --git a/gcr/tests/test-parser.c b/gcr/tests/test-parser.c
index b022fe3..18164a0 100644
--- a/gcr/tests/test-parser.c
+++ b/gcr/tests/test-parser.c
@@ -124,6 +124,9 @@ authenticate (GcrParser *par, gint state, gpointer user_data)
case 0:
gcr_parser_add_password (test->parser, "booo");
return TRUE;
+ case 1:
+ gcr_parser_add_password (test->parser, "usr0052");
+ return TRUE;
default:
g_printerr ("decryption didn't work for: %s", test->filedesc);
g_assert_not_reached ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]