[gnome-keyring/trust-store: 101/105] [egg] Implement egg_asn1x_set_raw_element() for explicitly tagged types.



commit 4f9355a1f2dc20839e1f123ba5f368556d4fe2ef
Author: Stef Walter <stefw collabora co uk>
Date:   Mon Nov 22 22:05:17 2010 +0000

    [egg] Implement egg_asn1x_set_raw_element() for explicitly tagged types.
    
    Also fix encoding of explicitly tagged choice elements.

 egg/egg-asn1x.c       |   98 +++++++++++++++++++++++++++++++++----------------
 egg/tests/test-asn1.c |   90 +++++++++++++++++++++++++++++++++++++++++++++
 egg/tests/test.asn    |    9 ++++
 3 files changed, 165 insertions(+), 32 deletions(-)
---
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 34eb457..f8c95a6 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 02fdced..758b62f 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 dca24d0..9779b37 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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]