summaryrefslogtreecommitdiff
path: root/egg
diff options
context:
space:
mode:
authorStef Walter <stefw@collabora.co.uk>2010-11-22 22:05:17 +0000
committerStef Walter <stefw@collabora.co.uk>2010-11-22 22:51:19 +0000
commit4f9355a1f2dc20839e1f123ba5f368556d4fe2ef (patch)
treea89c7bafec8fb86e03a4306fcfaf6f60c23d9299 /egg
parentd3c93154d373db7d1e817140f8e787836a1a807f (diff)
downloadgnome-keyring-4f9355a1f2dc20839e1f123ba5f368556d4fe2ef.tar.gz
[egg] Implement egg_asn1x_set_raw_element() for explicitly tagged types.
Also fix encoding of explicitly tagged choice elements.
Diffstat (limited to 'egg')
-rw-r--r--egg/egg-asn1x.c98
-rw-r--r--egg/tests/test-asn1.c90
-rw-r--r--egg/tests/test.asn9
3 files changed, 165 insertions, 32 deletions
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 34eb4575..f8c95a6b 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -1150,6 +1150,21 @@ egg_asn1x_decode (GNode *asn, gconstpointer data, gsize n_data)
* ENCODING
*/
+static GNode*
+find_chosen_with_tlv_for_choice (GNode *node)
+{
+ GNode *child;
+
+ g_assert (anode_def_type (node) == TYPE_CHOICE);
+
+ for (child = node->children; child; child = child->next) {
+ if (anode_get_tlv_data (child) != NULL)
+ return child;
+ }
+
+ return NULL;
+}
+
static void
anode_encode_length (gulong len, guchar *ans, gint *cb)
{
@@ -1304,7 +1319,6 @@ static gboolean
anode_encode_build (GNode *node, guchar *data, gsize n_data)
{
gint type;
- gint flags;
guchar cls;
gulong tag;
Aenc *enc;
@@ -1319,9 +1333,14 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
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 == TYPE_CHOICE) {
+ node = find_chosen_with_tlv_for_choice (node);
+ g_return_val_if_fail (node, FALSE);
+ }
+
/* Encode any explicit tag */
- flags = anode_def_flags (node);
- if (anode_calc_explicit_for_flags (node, flags)) {
+ if (anode_calc_explicit (node)) {
tag = anode_calc_tag (node);
g_return_val_if_fail (tag != G_MAXULONG, FALSE);
cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC);
@@ -1488,20 +1507,20 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
tlv = anode_get_tlv_data (node);
g_return_val_if_fail (tlv, FALSE);
- for (child = node->children; child; child = child->next) {
- ctlv = anode_get_tlv_data (child);
- if (ctlv) {
- enc = anode_get_enc_data (child);
- g_return_val_if_fail (enc, FALSE);
- if (!(enc->encoder) (enc->data, data, n_data))
- return FALSE;
+ child = find_chosen_with_tlv_for_choice (node);
+ g_return_val_if_fail (child, FALSE);
- /* Child's buffer matches ours */
- ctlv->buf = tlv->buf;
- ctlv->end = tlv->end;
- break;
- }
- }
+ ctlv = anode_get_tlv_data (child);
+ g_assert (ctlv);
+
+ enc = anode_get_enc_data (child);
+ g_return_val_if_fail (enc, FALSE);
+ if (!(enc->encoder) (enc->data, data, n_data))
+ return FALSE;
+
+ /* Child's buffer matches ours */
+ ctlv->buf = tlv->buf;
+ ctlv->end = tlv->end;
return TRUE;
}
@@ -1586,7 +1605,7 @@ anode_encode_prepare_structured (GNode *node)
if (type == TYPE_CHOICE) {
if (child) {
tlv = anode_get_tlv_data (child);
- g_return_val_if_fail (tlv, had);
+ g_return_val_if_fail (tlv, FALSE);
anode_clr_tlv_data (node);
anode_set_tlv_data (node, tlv);
anode_set_enc_data (node, anode_encoder_choice, node);
@@ -2605,37 +2624,52 @@ gboolean
egg_asn1x_set_raw_element (GNode *node, gpointer data,
gsize n_data, GDestroyNotify destroy)
{
- Atlv tlv;
+ Atlv dtlv, *tlv;
+ gint oft, flags;
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (data, FALSE);
g_return_val_if_fail (n_data, FALSE);
anode_clear (node);
- memset (&tlv, 0, sizeof (tlv));
-
- /* TODO: This needs implementation */
- if (anode_calc_explicit (node)) {
- g_warning ("egg_asn1x_set_raw_element does not yet work with explicit tagging");
- return FALSE;
- }
+ memset (&dtlv, 0, sizeof (dtlv));
/* Decode the beginning TLV */
- if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &tlv))
+ if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &dtlv))
return FALSE;
- /* Decode the data into place properly */
- if (!anode_decode_anything (node, &tlv))
+ /*
+ * 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, &dtlv, flags))
return FALSE;
/* There was extra data */
- if (tlv.end - tlv.buf != n_data)
+ if (dtlv.end - dtlv.buf != n_data)
return FALSE;
- /* Should have been set above */
- g_assert (anode_get_tlv_data (node) != NULL);
+ /* Clear buffer from TLV so it gets encoded */
+ tlv = anode_get_tlv_data (node);
+ g_assert (tlv);
+ tlv->buf = tlv->end = NULL;
+
+ /* Explicit tagging: leave space for the outer tag */
+ if (anode_calc_explicit (node)) {
+ oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC),
+ anode_calc_tag (node), n_data);
+
+ tlv->off += oft;
+ tlv->oft = oft;
+ }
- /* We set this so the data is properly destroyed */
+ /* Setup encoding of the contents */
+ anode_set_enc_data (node, anode_encoder_simple, (gpointer)(dtlv.buf + dtlv.off));
anode_set_user_data (node, data, destroy);
return TRUE;
}
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index 02fdcedb..758b62fa 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -398,6 +398,9 @@ DEFINE_TEST(asn1_any_set_raw)
const guchar *check;
gsize n_data, n_check;
+ /* ENCODED SEQUENCE ANY with OCTET STRING */
+ const gchar SEQ_ENCODING[] = "\x30\x0C\x04\x0A""farnsworth";
+
asn = egg_asn1x_create (test_asn1_tab, "TestAnySeq");
g_assert (asn);
@@ -411,6 +414,81 @@ DEFINE_TEST(asn1_any_set_raw)
data = egg_asn1x_encode (asn, NULL, &n_data);
g_assert (data);
+ g_assert_cmpsize (n_data, ==, XL (SEQ_ENCODING));
+ g_assert (memcmp (data, SEQ_ENCODING, n_data) == 0);
+
+ check = egg_asn1x_get_raw_element (node, &n_check);
+ g_assert (check);
+
+ g_assert_cmpsize (n_check, ==, XL (SFARNSWORTH));
+ g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+
+ g_free (data);
+ egg_asn1x_destroy (asn);
+ g_assert (is_freed);
+}
+
+DEFINE_TEST(asn1_any_set_raw_explicit)
+{
+ GNode *asn, *node;
+ guchar *data;
+ const guchar *check;
+ gsize n_data, n_check;
+
+ /* ENCODED SEQUENCE [89] ANY with OCTET STRING */
+ const gchar SEQ_ENCODING[] = "\x30\x0F\xBF\x59\x0C\x04\x0A""farnsworth";
+
+ asn = egg_asn1x_create (test_asn1_tab, "TestAnyExp");
+ g_assert (asn);
+
+ is_freed = FALSE;
+ node = egg_asn1x_node (asn, "contents", NULL);
+ g_assert (node);
+
+ if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+ g_assert_not_reached ();
+
+ data = egg_asn1x_encode (asn, NULL, &n_data);
+ g_assert (data);
+
+ g_assert_cmpsize (n_data, ==, XL (SEQ_ENCODING));
+ g_assert (memcmp (data, SEQ_ENCODING, n_data) == 0);
+
+ check = egg_asn1x_get_raw_element (node, &n_check);
+ g_assert (check);
+
+ g_assert (n_check == XL (SFARNSWORTH));
+ g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+
+ g_free (data);
+ egg_asn1x_destroy (asn);
+ g_assert (is_freed);
+}
+
+static void
+perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsize n_encoding)
+{
+ GNode *asn, *node;
+ guchar *data;
+ const guchar *check;
+ gsize n_data, n_check;
+
+ asn = egg_asn1x_create (test_asn1_tab, "TestAnyChoice");
+ g_assert (asn);
+
+ is_freed = FALSE;
+ node = egg_asn1x_node (asn, choice, NULL);
+ g_assert (node);
+
+ if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+ g_assert_not_reached ();
+
+ data = egg_asn1x_encode (asn, NULL, &n_data);
+ g_assert (data);
+
+ g_assert_cmpsize (n_data, ==, n_encoding);
+ g_assert (memcmp (data, encoding, n_data) == 0);
+
check = egg_asn1x_get_raw_element (node, &n_check);
g_assert (check);
@@ -422,6 +500,18 @@ DEFINE_TEST(asn1_any_set_raw)
g_assert (is_freed);
}
+DEFINE_TEST(asn1_any_choice_set_raw_short_tag)
+{
+ const gchar ENCODING[] = "\xBE\x0C\x04\x0A""farnsworth";
+ perform_asn1_any_choice_set_raw ("choiceShortTag", ENCODING, XL (ENCODING));
+}
+
+DEFINE_TEST(asn1_any_choice_set_raw_long_tag)
+{
+ const gchar ENCODING[] = "\xBF\x1F\x0C\x04\x0A""farnsworth";
+ perform_asn1_any_choice_set_raw ("choiceLongTag", ENCODING, XL (ENCODING));
+}
+
DEFINE_TEST(asn1_append)
{
GNode *asn;
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index dca24d07..9779b378 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -40,6 +40,15 @@ TestAnySeq ::= SEQUENCE {
contents ANY
}
+TestAnyExp ::= SEQUENCE {
+ contents [89] ANY
+}
+
+TestAnyChoice ::= CHOICE {
+ choiceShortTag [30] ANY,
+ choiceLongTag [31] ANY
+}
+
TestSeqOf ::= SEQUENCE OF INTEGER
TestSetOf ::= SET OF INTEGER