diff options
-rw-r--r-- | egg/egg-asn1x.c | 3132 | ||||
-rw-r--r-- | egg/egg-asn1x.h | 60 | ||||
-rw-r--r-- | egg/egg-dn.c | 50 | ||||
-rw-r--r-- | egg/egg-dn.h | 4 | ||||
-rw-r--r-- | egg/egg-symkey.c | 82 | ||||
-rw-r--r-- | egg/egg-symkey.h | 12 | ||||
-rw-r--r-- | egg/tests/test-asn1.c | 93 | ||||
-rw-r--r-- | egg/tests/test-asn1x.c | 140 | ||||
-rw-r--r-- | egg/tests/test-dn.c | 19 | ||||
-rw-r--r-- | egg/tests/test.asn | 3 | ||||
-rw-r--r-- | pkcs11/gkm/gkm-certificate.c | 4 | ||||
-rw-r--r-- | pkcs11/gkm/gkm-data-asn1.c | 2 | ||||
-rw-r--r-- | pkcs11/gkm/gkm-data-der.c | 48 | ||||
-rw-r--r-- | pkcs11/gkm/tests/test-data-der.c | 4 | ||||
-rw-r--r-- | pkcs11/xdg-store/gkm-xdg-trust.c | 8 | ||||
-rw-r--r-- | pkcs11/xdg-store/tests/frob-trust-file.c | 8 |
16 files changed, 1928 insertions, 1741 deletions
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c index 2a3f276b..6a1f3791 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,38 @@ 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 */ + + /* Encoding: for bitstring, the number of empty bits at end */ + guint bits_empty : 3; + + /* Encoding: tell us whether we're dealing with a bit string */ + guint prefix_for_bit_string : 1; + + /* Encoding: prefix a zero byte for unsigned integers */ + guint prefix_with_zero_byte : 1; + + /* Encoding: sort children of this tlv (ie: SETOF) */ + guint sorted : 1; }; struct _Anode { @@ -136,31 +146,28 @@ struct _Anode { const EggAsn1xDef *join; GList *opts; - Atlv *tlv; - Aenc *enc; + GBytes *value; + Atlv *parsed; - GBytes *backing; gchar* failure; - gint chosen : 1; -}; + /* If this node was chosen out of a choice */ + guint chosen : 1; -struct _Abuf { - guchar* data; - gsize n_data; - gpointer user_data; -}; + /* For bitstring the number of empty bits */ + guint bits_empty : 3; -struct _Abits { - guint n_bits; - GBytes *bits; + /* Whether we need to prefix a zero byte to make unsigned */ + 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 +182,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 +413,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 +536,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 +552,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 +592,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 +656,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 +703,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 +719,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 +753,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 +765,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 +927,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 +942,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 +984,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 +1001,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)) { - definite = (tlv->len >= 0); - end = tlv->end; + /* 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"); + } +} + +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 +1157,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; + + 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; - if (!anode_decode_anything_for_flags (node, bytes, tlv, flags)) - return anode_decode_option_or_default (node, tlv, flags); + /* 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); + tlv = atlv_new (); + msg = atlv_parse_der (data, tlv); + if (msg == NULL) { + ret = anode_decode_anything (asn, tlv); - if (!anode_decode_tlv_for_data (dat, dat + size, &tlv)) - return anode_failure (asn, "content is not encoded properly"); - - 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 +1310,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 +1347,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,421 +1355,316 @@ 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; - - tlv = anode_get_tlv_data (node); - if (tlv == NULL) - return FALSE; + Atlv *parsed; - /* 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. It is assumed + * that any explicit tags are already present, and the functions + * for managing ANY try to enforce this. + */ - 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); - } + parsed = anode_get_parsed (node); + if (parsed != NULL) + return atlv_dup (parsed, FALSE); - 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); @@ -1744,127 +1673,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, so just return */ + 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 * @@ -1872,44 +1817,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 @@ -2166,23 +2096,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); @@ -2204,29 +2139,35 @@ 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; guchar *at; gboolean sign; + gsize len; for (i = 0; i < sizeof (gulong); ++i) { off = sizeof (gulong) - (i + 1); @@ -2244,9 +2185,10 @@ anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data) /* If the first byte would make this negative, then add a zero */ at = buf + (sizeof (gulong) - bytes); sign = !!(at[0] & 0x80); + len = bytes + (sign ? 1 : 0); if (data) { - g_assert (*n_data >= bytes + 1); + g_assert (*n_data >= len); if (sign) { data[0] = 0; data++; @@ -2254,78 +2196,137 @@ anode_write_integer_ulong (gulong value, guchar *data, gsize *n_data) memcpy (data, at, bytes); } - *n_data = bytes + (sign ? 1 : 0); - return TRUE; + *n_data = len; +} + +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); + + 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); } static gboolean -anode_read_string (GNode *node, Atlv *tlv, gpointer value, gsize *n_value) +anode_read_string_struct (GNode *node, + Atlv *tlv, + gpointer value, + gsize *n_value) { - Atlv ctlv; - guchar *buf; - gint n_buf; - gint i; + const guchar *buf; + gsize len; + Atlv *ctlv; + guchar *at; + gint remaining; - g_assert (tlv); - g_assert (n_value); + g_assert (tlv != NULL); + g_assert (tlv->cls & ASN1_CLASS_STRUCTURED); + g_assert (n_value != NULL); - buf = value; - n_buf = *n_value; + at = value; + remaining = *n_value; + *n_value = 0; - /* 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) + 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; + } + } - /* 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); + if (value && remaining < 0) + return FALSE; + + return TRUE; +} + +static gboolean +anode_read_string_simple (GNode *node, + GBytes *data, + gpointer value, + gsize *n_value) +{ + const guchar *buf; + gsize len; + + g_assert (data != NULL); + g_assert (n_value != NULL); + + buf = g_bytes_get_data (data, &len); + if (value) { + if (*n_value < len) { + *n_value = len; + return FALSE; } + 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; - if (tlv->len != 1) + g_assert (node != NULL); + g_assert (data != NULL); + g_assert (value != NULL); + + 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); @@ -2335,22 +2336,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); @@ -2362,7 +2392,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"); @@ -2384,7 +2414,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; @@ -2396,7 +2426,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; @@ -2451,6 +2483,10 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data) return TRUE; } +/* ----------------------------------------------------------------------------------- + * GETTING, SETTING + */ + GNode* egg_asn1x_node (GNode *asn, ...) { @@ -2506,14 +2542,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); } @@ -2568,77 +2604,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 @@ -2647,21 +2690,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 */ @@ -2676,8 +2716,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; @@ -2685,156 +2726,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 @@ -2851,6 +2879,7 @@ 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); @@ -2866,8 +2895,11 @@ egg_asn1x_take_integer_as_raw (GNode *node, return; } - anode_encode_tlv_and_enc (node, g_bytes_get_size (value), anode_encoder_bytes, - value, (GDestroyNotify)g_bytes_unref); + anode_clr_value (node); + anode_set_value (node, value); + + an = node->data; + an->guarantee_unsigned = 0; } void @@ -2882,153 +2914,209 @@ void egg_asn1x_take_integer_as_usg (GNode *node, GBytes *value) { - gboolean sign; - const guchar *p; - gsize len; + 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); - len = g_bytes_get_size (value); + anode_set_value (node, value); + an = node->data; + an->guarantee_unsigned = 1; +} - /* - * 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; +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); - anode_encode_tlv_and_enc (node, len, anode_encoder_unsigned, - value, (GDestroyNotify)g_bytes_unref); + return egg_asn1x_get_any_as_full (node, defs, type, 0); } -GBytes * -egg_asn1x_get_element_raw (GNode *node) +GNode * +egg_asn1x_get_any_as_full (GNode *node, + const EggAsn1xDef *defs, + const gchar *type, + gint options) { - GBytes *backing; - const guchar *p; - gsize len; - Atlv *tlv; + 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); - tlv = anode_get_tlv_data (node); - if (tlv == NULL || tlv->buf == NULL) - return NULL; + asn = egg_asn1x_create (defs, type); + g_return_val_if_fail (asn != NULL, NULL); - backing = anode_get_backing (node); - if (backing == NULL) + if (!egg_asn1x_get_any_into_full (node, asn, options)) { + egg_asn1x_destroy (asn); 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)); + return asn; } gboolean -egg_asn1x_set_element_raw (GNode *node, - GBytes *element) +egg_asn1x_get_any_into (GNode *node, + GNode *into) { - Atlv dtlv, *tlv; - gint oft, flags; - const guchar *data; - guchar cls_type; - GBytes *sub; - gsize size; - g_return_val_if_fail (node != NULL, FALSE); - g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (into != NULL, FALSE); + g_return_val_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY, FALSE); - anode_clear (node); - memset (&dtlv, 0, sizeof (dtlv)); + return egg_asn1x_get_any_into_full (node, into, 0); +} - data = g_bytes_get_data (element, &size); - g_return_val_if_fail (data != NULL, FALSE); +gboolean +egg_asn1x_get_any_into_full (GNode *node, + GNode *into, + gint options) +{ + Atlv *tlv; - /* Decode the beginning TLV */ - if (!anode_decode_tlv_for_data (data, data + size, &dtlv)) - return FALSE; + 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); - /* - * 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)) + tlv = anode_get_parsed (node); + if (tlv == NULL) return FALSE; - /* There was extra data */ - if (dtlv.end - dtlv.buf != size) + /* 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; + } + + if (!anode_decode_anything (into, tlv)) return FALSE; - /* Clear buffer from TLV so it gets encoded */ - tlv = anode_get_tlv_data (node); - g_assert (tlv); - tlv->buf = tlv->end = NULL; + return egg_asn1x_validate (into, !(options & EGG_ASN1X_NO_STRICT)); +} - /* 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); +void +egg_asn1x_set_any_from (GNode *node, + GNode *from) +{ + Anode *an; + Atlv *tlv; - tlv->off += oft; - tlv->oft = oft; - } + g_return_if_fail (node != NULL); + g_return_if_fail (from != NULL); + g_return_if_fail (egg_asn1x_type (node) == EGG_ASN1X_ANY); - sub = g_bytes_new_with_free_func (dtlv.buf + dtlv.off, dtlv.len, - (GDestroyNotify)g_bytes_unref, - g_bytes_ref (element)); + tlv = anode_build_anything (from, TRUE); + g_return_if_fail (tlv != NULL); - /* Setup encoding of the contents */ - anode_set_enc_data (node, anode_encoder_bytes, sub, (GDestroyNotify)g_bytes_unref); - return TRUE; + /* Wrap this in an explicit tag if necessary */ + tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node)); + + /* Mark down the tlvs for this node */ + an = node->data; + atlv_free (an->parsed); + an->parsed = tlv; } GBytes * -egg_asn1x_get_raw_value (GNode *node) +egg_asn1x_get_any_raw (GNode *node, + EggAllocator allocator) { - GBytes *backing; + GBytes *bytes; 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) + tlv = anode_build_anything (node, TRUE); + if (tlv == NULL) { + anode_failure (node, "missing value(s)"); return NULL; - g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL); + } + + atlv_sort_perform (tlv, allocator); + + bytes = atlv_unparse_to_bytes (tlv, allocator); + atlv_free (tlv); + return bytes; +} - backing = anode_get_backing (node); - if (backing == NULL) +gboolean +egg_asn1x_set_any_raw (GNode *node, + GBytes *raw) +{ + const gchar *msg; + Anode *an; + Atlv *tlv; + + g_return_val_if_fail (node != NULL, FALSE); + g_return_val_if_fail (raw != NULL, FALSE); + + an = node->data; + tlv = atlv_new (); + msg = atlv_parse_der (raw, tlv); + if (msg == NULL) { + + /* Wrap this in an explicit tag if necessary */ + tlv = anode_build_maybe_explicit (node, tlv, anode_def_flags (node)); + + atlv_free (an->parsed); + an->parsed = tlv; + return TRUE; + + /* 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; + } +} + +GBytes * +egg_asn1x_get_element_raw (GNode *node) +{ + Anode *an; + Atlv *tlv; + + g_return_val_if_fail (node != NULL, 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; + + 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); } -guchar* -egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_string) +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) { gsize length; guchar *string; + GBytes *data; Atlv *tlv; gint type; @@ -3039,43 +3127,83 @@ 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)); +} + +void +egg_asn1x_set_string_as_bytes (GNode *node, + GBytes *bytes) +{ + gint type; + + g_return_if_fail (node != NULL); + g_return_if_fail (bytes != NULL); + + type = anode_def_type (node); + g_return_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING); + + anode_set_value (node, g_bytes_ref (bytes)); } GBytes * @@ -3093,23 +3221,6 @@ egg_asn1x_get_string_as_bytes (GNode *node) return g_bytes_new_take (raw, length); } -gboolean -egg_asn1x_set_string_as_bytes (GNode *node, - GBytes *data) -{ - gint type; - - g_return_val_if_fail (node != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - - type = anode_def_type (node); - g_return_val_if_fail (type == EGG_ASN1X_OCTET_STRING || type == EGG_ASN1X_GENERALSTRING, FALSE); - - anode_encode_tlv_and_enc (node, g_bytes_get_size (data), anode_encoder_bytes, - g_bytes_ref (data), (GDestroyNotify)g_bytes_unref); - return TRUE; -} - gchar * egg_asn1x_get_bmpstring_as_utf8 (GNode *node) { @@ -3130,7 +3241,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; @@ -3153,47 +3265,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 @@ -3201,7 +3310,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); } @@ -3210,9 +3321,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); @@ -3220,47 +3332,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; @@ -3268,47 +3387,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; @@ -3326,20 +3443,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; @@ -3357,11 +3475,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); @@ -3371,42 +3489,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; } @@ -3425,13 +3544,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); } @@ -3455,12 +3576,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 */ @@ -3485,7 +3607,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; @@ -3509,7 +3633,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; @@ -3535,23 +3660,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 */ @@ -3560,7 +3688,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; } @@ -3575,82 +3703,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; - if (!anode_validate_integer (node, tlv)) + g_assert (value != NULL); + + 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 @@ -3684,25 +3818,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; } } @@ -3714,36 +3835,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++; } } @@ -3754,51 +3855,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); @@ -3808,8 +3875,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 @@ -4186,25 +4299,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); } /* ----------------------------------------------------------------------------------- @@ -4242,7 +4370,6 @@ traverse_and_dump (GNode *node, gpointer unused) guint i, depth; GString *output; gchar *string; - Atlv *tlv; Anode *an; GList *l; @@ -4250,18 +4377,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 (" "); @@ -4433,9 +4559,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; @@ -4461,11 +4587,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 f4d4da9d..0320a0c3 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,8 +84,34 @@ 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); @@ -107,20 +142,20 @@ 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); @@ -139,26 +174,23 @@ 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); - 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); -gboolean egg_asn1x_set_string_as_bytes (GNode *node, - GBytes *data); +void egg_asn1x_set_string_as_bytes (GNode *node, + GBytes *bytes); GBytes * egg_asn1x_get_bits_as_raw (GNode *node, guint *n_bits); @@ -175,7 +207,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 e3b092ef..43bd772f 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 a75e73dd..bdf6b921 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 8d4865c1..54592d97 100644 --- a/egg/egg-symkey.c +++ b/egg/egg-symkey.c @@ -2,8 +2,8 @@ * gnome-keyring * * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify + * + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. @@ -12,8 +12,8 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General + * + * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. @@ -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); - - asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-rc2-CBC-params"); - g_return_val_if_fail (asn, FALSE); + g_assert (any != NULL); - 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 a7410ae4..f4938f6a 100644 --- a/egg/egg-symkey.h +++ b/egg/egg-symkey.h @@ -2,8 +2,8 @@ * gnome-keyring * * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify + * + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. @@ -12,8 +12,8 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General + * + * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. @@ -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/test-asn1.c b/egg/tests/test-asn1.c index 6a71b9e5..13130994 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); @@ -626,8 +621,8 @@ test_any_set_raw (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)) + test_is_freed, NULL); + 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 4581756b..ad75e625 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 cf83dcb7..6494679b 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 5412a637..04653285 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/pkcs11/gkm/gkm-certificate.c b/pkcs11/gkm/gkm-certificate.c index e2936f39..481c2e76 100644 --- a/pkcs11/gkm/gkm-certificate.c +++ b/pkcs11/gkm/gkm-certificate.c @@ -556,8 +556,8 @@ gkm_certificate_get_extension (GkmCertificate *self, GQuark oid, } /* And the extension value */ - return egg_asn1x_get_raw_value (egg_asn1x_node (self->pv->asn1, "tbsCertificate", - "extensions", index, "extnValue", NULL)); + return egg_asn1x_get_string_as_bytes (egg_asn1x_node (self->pv->asn1, "tbsCertificate", + "extensions", index, "extnValue", NULL)); } const gchar* diff --git a/pkcs11/gkm/gkm-data-asn1.c b/pkcs11/gkm/gkm-data-asn1.c index 49629c40..8e31bf75 100644 --- a/pkcs11/gkm/gkm-data-asn1.c +++ b/pkcs11/gkm/gkm-data-asn1.c @@ -37,7 +37,7 @@ gkm_data_asn1_read_mpi (GNode *asn, gcry_mpi_t *mpi) g_return_val_if_fail (asn, FALSE); g_return_val_if_fail (mpi, FALSE); - buf = egg_asn1x_get_raw_value (asn); + buf = egg_asn1x_get_integer_as_raw (asn); if (!buf) return FALSE; diff --git a/pkcs11/gkm/gkm-data-der.c b/pkcs11/gkm/gkm-data-der.c index 62114250..6130d098 100644 --- a/pkcs11/gkm/gkm-data-der.c +++ b/pkcs11/gkm/gkm-data-der.c @@ -525,7 +525,7 @@ gkm_data_der_read_private_pkcs8_plain (GBytes *data, 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; @@ -577,7 +577,7 @@ gkm_data_der_read_private_pkcs8_crypted (GBytes *data, GkmDataResult ret, r; GQuark scheme; guchar *crypted = NULL; - GBytes *params; + GNode *params; GBytes *bytes; gsize n_crypted; gint l; @@ -597,7 +597,7 @@ gkm_data_der_read_private_pkcs8_crypted (GBytes *data, 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); if (!params) goto done; @@ -605,7 +605,6 @@ gkm_data_der_read_private_pkcs8_crypted (GBytes *data, * Parse the encryption stuff into a cipher. */ r = egg_symkey_read_cipher (scheme, password, n_password, params, &cih); - g_bytes_unref (params); if (r == GKM_DATA_UNRECOGNIZED) { ret = GKM_DATA_FAILURE; @@ -747,8 +746,7 @@ gkm_data_der_write_private_key_rsa (gcry_sexp_t s_key) goto done; /* Write out the version */ - if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0)) - goto done; + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0); result = egg_asn1x_encode (asn, egg_secure_realloc); if (result == NULL) @@ -794,8 +792,7 @@ gkm_data_der_write_public_key_dsa (gcry_sexp_t s_key) !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "Y", NULL), y)) goto done; - if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0)) - goto done; + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0); result = egg_asn1x_encode (asn, NULL); if (result == NULL) @@ -901,8 +898,7 @@ gkm_data_der_write_private_key_dsa (gcry_sexp_t s_key) !gkm_data_asn1_write_mpi (egg_asn1x_node (asn, "priv", NULL), x)) goto done; - if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0)) - goto done; + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0); result = egg_asn1x_encode (asn, egg_secure_realloc); if (result == NULL) @@ -974,7 +970,6 @@ prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password, guchar salt[8]; gcry_error_t gcry; guchar *key, *iv; - GBytes *portion; gsize n_key; int iterations; @@ -1006,20 +1001,9 @@ prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password, /* Now write out the parameters */ asn1_params = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PbeParams"); g_return_val_if_fail (asn1_params, NULL); - if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, sizeof (salt), NULL)) - g_return_val_if_reached (NULL); - if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations)) - g_return_val_if_reached (NULL); - portion = egg_asn1x_encode (asn1_params, NULL); - if (portion == NULL) { - g_warning ("couldn't encode pkcs8 params key: %s", egg_asn1x_message (asn1_params)); - g_return_val_if_reached (NULL); - } - - if (!egg_asn1x_set_element_raw (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), - portion)) - g_return_val_if_reached (NULL); - g_bytes_unref (portion); + egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, sizeof (salt), NULL); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations); + egg_asn1x_set_any_from (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), asn1_params); /* Now make a cipher that matches what we wrote out */ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0); @@ -1058,8 +1042,7 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey) g_return_val_if_fail (asn, NULL); /* Write out the version */ - if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0)) - g_return_val_if_reached (NULL); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), 0); /* Per algorithm differences */ switch (algorithm) @@ -1089,16 +1072,12 @@ gkm_data_der_write_private_pkcs8_plain (gcry_sexp_t skey) /* Write out the parameters */ if (params) { - if (!egg_asn1x_set_element_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), - params)) - g_return_val_if_reached (NULL); + egg_asn1x_set_any_raw (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), params); g_bytes_unref (params); } /* Write out the key portion */ - if (!egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL), key)) - g_return_val_if_reached (NULL); - + egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "privateKey", NULL), key); g_bytes_unref (key); data = egg_asn1x_encode (asn, egg_secure_realloc); @@ -1161,8 +1140,7 @@ gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, gcry_cipher_close (cih); key = g_bytes_new_with_free_func (raw, n_raw, egg_secure_free, raw); - if (!egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "encryptedData", NULL), key)) - g_return_val_if_reached (NULL); + egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "encryptedData", NULL), key); g_bytes_unref (key); diff --git a/pkcs11/gkm/tests/test-data-der.c b/pkcs11/gkm/tests/test-data-der.c index 2370c1ef..03407392 100644 --- a/pkcs11/gkm/tests/test-data-der.c +++ b/pkcs11/gkm/tests/test-data-der.c @@ -373,7 +373,7 @@ find_extension (GNode *asn, if (strcmp (exoid, oid) == 0) { g_free (exoid); node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, "extnValue", NULL); - value = egg_asn1x_get_raw_value (node); + value = egg_asn1x_get_any_raw (node, NULL); g_assert (value); return value; } @@ -392,7 +392,7 @@ test_read_basic_constraints (Test *test, gconstpointer unused) gint path_len; GkmDataResult res; - extension = egg_asn1x_get_raw_value (egg_asn1x_node (test->certificate, "tbsCertificate", "extensions", 1, "extnValue", NULL)); + extension = egg_asn1x_get_any_raw (egg_asn1x_node (test->certificate, "tbsCertificate", "extensions", 1, "extnValue", NULL), NULL); g_assert (extension != NULL); res = gkm_data_der_read_basic_constraints (extension, &is_ca, &path_len); diff --git a/pkcs11/xdg-store/gkm-xdg-trust.c b/pkcs11/xdg-store/gkm-xdg-trust.c index d885bbd7..d8d10f85 100644 --- a/pkcs11/xdg-store/gkm-xdg-trust.c +++ b/pkcs11/xdg-store/gkm-xdg-trust.c @@ -503,9 +503,9 @@ save_assertion (GNode *asn, GkmAssertion *assertion) peer = gkm_assertion_get_peer (assertion); if (!egg_asn1x_set_string_as_utf8 (egg_asn1x_node (asn, "purpose", NULL), - g_strdup (purpose), g_free) || - !egg_asn1x_set_enumerated (egg_asn1x_node (asn, "level", NULL), level)) + g_strdup (purpose), g_free)) g_return_val_if_reached (FALSE); + egg_asn1x_set_enumerated (egg_asn1x_node (asn, "level", NULL), level); if (peer && !egg_asn1x_set_string_as_utf8 (egg_asn1x_node (asn, "peer", NULL), g_strdup (peer), g_free)) @@ -557,7 +557,7 @@ create_trust_for_reference (GkmModule *module, GkmManager *manager, g_bytes_unref (bytes); bytes = g_bytes_new (issuer->pValue, issuer->ulValueLen); - egg_asn1x_set_element_raw (egg_asn1x_node (node, "issuer", NULL), bytes); + egg_asn1x_set_any_raw (egg_asn1x_node (node, "issuer", NULL), bytes); g_bytes_unref (bytes); trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL); @@ -589,7 +589,7 @@ create_trust_for_complete (GkmModule *module, GkmManager *manager, egg_asn1x_set_choice (ref, node); bytes = g_bytes_new (cert->pValue, cert->ulValueLen); - egg_asn1x_set_element_raw (node, bytes); + egg_asn1x_set_any_raw (node, bytes); g_bytes_unref (bytes); trust = g_object_new (GKM_XDG_TYPE_TRUST, "module", module, "manager", manager, NULL); diff --git a/pkcs11/xdg-store/tests/frob-trust-file.c b/pkcs11/xdg-store/tests/frob-trust-file.c index a6d226a5..79232c6a 100644 --- a/pkcs11/xdg-store/tests/frob-trust-file.c +++ b/pkcs11/xdg-store/tests/frob-trust-file.c @@ -68,7 +68,7 @@ create_trust_file_for_certificate (const gchar *filename, const gchar *certifica ref = egg_asn1x_node (asn, "reference", NULL); choice = egg_asn1x_node (ref, "certComplete", NULL); - if (!egg_asn1x_set_choice (ref, choice) || !egg_asn1x_set_element_raw (choice, bytes)) + if (!egg_asn1x_set_choice (ref, choice) || !egg_asn1x_set_any_raw (choice, bytes)) g_return_if_reached (); g_bytes_unref (bytes); @@ -129,7 +129,7 @@ create_trust_file_for_issuer_and_serial (const gchar *filename, const gchar *cer /* Copy over the serial and issuer */ element = egg_asn1x_get_element_raw (issuer); - if (!egg_asn1x_set_element_raw (egg_asn1x_node (choice, "issuer", NULL), element)) + if (!egg_asn1x_set_any_raw (egg_asn1x_node (choice, "issuer", NULL), element)) g_return_if_reached (); g_bytes_unref (element); @@ -178,9 +178,9 @@ add_trust_purpose_to_file (const gchar *filename, const gchar *purpose) assertion = egg_asn1x_append (egg_asn1x_node (asn, "assertions", NULL)); g_return_if_fail (assertion); - if (!egg_asn1x_set_string_as_utf8 (egg_asn1x_node (assertion, "purpose", NULL), g_strdup (purpose), g_free) || - !egg_asn1x_set_enumerated (egg_asn1x_node (assertion, "level", NULL), g_quark_from_string ("trusted"))) + if (!egg_asn1x_set_string_as_utf8 (egg_asn1x_node (assertion, "purpose", NULL), g_strdup (purpose), g_free)) g_return_if_reached (); + egg_asn1x_set_enumerated (egg_asn1x_node (assertion, "level", NULL), g_quark_from_string ("trusted")); result = egg_asn1x_encode (asn, NULL); if (result == NULL) |