[gcr] egg: Encode DER tag classes correctly



commit 77bbfca91cba5e9428c0c716a1a5cd82ae40717b
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Nov 17 10:31:37 2011 +0100

    egg: Encode DER tag classes correctly
    
     * Encode DER tag classes correctly for universal, application
       and private classes

 egg/egg-asn1x.c       |   38 ++++++++++++++------
 egg/tests/test-asn1.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++---
 egg/tests/test.asn    |    2 +
 3 files changed, 119 insertions(+), 16 deletions(-)
---
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index 8638c37..5a7db21 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -601,22 +601,35 @@ anode_calc_tag (GNode *node)
 }
 
 static gboolean
-anode_calc_explicit_for_flags (GNode *node, gint flags)
+anode_calc_explicit_for_flags (GNode *node,
+                               gint flags,
+                               guchar *cls_type)
 {
 	const EggAsn1xDef *opt;
 	if ((flags & FLAG_TAG) != FLAG_TAG)
 		return FALSE;
 	opt = anode_opt_lookup (node, EGG_ASN1X_TAG, NULL);
 	g_return_val_if_fail (opt, FALSE);
+	if (cls_type) {
+		if (opt->type & FLAG_UNIVERSAL)
+			*cls_type = ASN1_CLASS_UNIVERSAL;
+		else if (opt->type & FLAG_APPLICATION)
+			*cls_type = ASN1_CLASS_APPLICATION;
+		else if (opt->type & FLAG_PRIVATE)
+			*cls_type = ASN1_CLASS_PRIVATE;
+		else
+			*cls_type = ASN1_CLASS_CONTEXT_SPECIFIC;
+	}
 	if ((opt->type & FLAG_IMPLICIT) == FLAG_IMPLICIT)
 		return FALSE;
 	return TRUE;
 }
 
 static gboolean
-anode_calc_explicit (GNode *node)
+anode_calc_explicit (GNode *node,
+                     guchar *cls_type)
 {
-	return anode_calc_explicit_for_flags (node, anode_def_flags (node));
+	return anode_calc_explicit_for_flags (node, anode_def_flags (node), cls_type);
 }
 
 /* -------------------------------------------------------------------------
@@ -1057,7 +1070,7 @@ anode_decode_structured (GNode *node,
 	end = tlv->end;
 
 	/* An explicit, wrapped tag */
-	if (anode_calc_explicit_for_flags (node, flags)) {
+	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))
@@ -1314,6 +1327,7 @@ anode_encode_tlv_and_enc (GNode *node,
                           GDestroyNotify destroy)
 {
 	gboolean explicit = FALSE;
+	guchar cls_type;
 	gulong tag;
 	gint flags;
 	Atlv tlv;
@@ -1358,11 +1372,11 @@ anode_encode_tlv_and_enc (GNode *node,
 	/* Build up the class */
 	flags = anode_def_flags (node);
 	if (flags & FLAG_TAG) {
-		explicit = anode_calc_explicit_for_flags (node, flags);
+		explicit = anode_calc_explicit_for_flags (node, flags, &cls_type);
 		if (explicit)
 			flags &= ~FLAG_TAG;
 		else
-			tlv.cls |= ASN1_CLASS_CONTEXT_SPECIFIC;
+			tlv.cls |= cls_type;
 	}
 
 	/* And now the tag */
@@ -1393,6 +1407,7 @@ anode_encode_build (GNode *node,
                     guchar *data,
                     gsize n_data)
 {
+	guchar cls_type;
 	gint type;
 	guchar cls;
 	gulong tag;
@@ -1415,10 +1430,10 @@ anode_encode_build (GNode *node,
 	}
 
 	/* Encode any explicit tag */
-	if (anode_calc_explicit (node)) {
+	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 | ASN1_CLASS_CONTEXT_SPECIFIC);
+		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);
@@ -2895,7 +2910,7 @@ egg_asn1x_get_element_raw (GNode *node)
 	if (backing == NULL)
 		return NULL;
 
-	if (anode_calc_explicit (node)) {
+	if (anode_calc_explicit (node, NULL)) {
 		len = (tlv->len + tlv->off) - tlv->oft;
 		p = tlv->buf + tlv->oft;
 	} else {
@@ -2914,6 +2929,7 @@ egg_asn1x_set_element_raw (GNode *node,
 	Atlv dtlv, *tlv;
 	gint oft, flags;
 	const guchar *data;
+	guchar cls_type;
 	EggBytes *sub;
 	gsize size;
 
@@ -2952,8 +2968,8 @@ egg_asn1x_set_element_raw (GNode *node,
 	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),
+	if (anode_calc_explicit (node, &cls_type)) {
+		oft = anode_encode_cls_tag_len (NULL, 0, (ASN1_CLASS_STRUCTURED | cls_type),
 		                                anode_calc_tag (node), size);
 
 		tlv->off += oft;
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index caf01af..7844c92 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -42,7 +42,8 @@ const gchar BFALSE[] =        "\x01\x01\x00";
 const gchar BTRUE[] =         "\x01\x01\xFF";
 const gchar SFARNSWORTH[] =   "\x04\x0A""farnsworth";
 const gchar SIMPLICIT[] =     "\x85\x08""implicit";
-const gchar SEXPLICIT[] =     "\xE5\x0A\x04\x08""explicit";
+const gchar SEXPLICIT[] =     "\xA5\x0A\x04\x08""explicit";
+const gchar SUNIVERSAL[] =    "\x05\x09""universal";
 const gchar TGENERALIZED[] =  "\x18\x0F""20070725130528Z";
 const gchar BITS_TEST[] =  "\x03\x04\x06\x6e\x5d\xc0";
 const gchar BITS_BAD[] =  "\x03\x04\x06\x6e\x5d\xc1";
@@ -285,7 +286,7 @@ test_generalized_time (void)
 }
 
 static void
-test_implicit (void)
+test_implicit_encode (void)
 {
 	EggBytes *bytes;
 	GNode *asn;
@@ -307,7 +308,26 @@ test_implicit (void)
 }
 
 static void
-test_explicit (void)
+test_implicit_decode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestImplicit");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("implicit"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SIMPLICIT, XL (SIMPLICIT));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
+test_explicit_decode (void)
 {
 	EggBytes *bytes;
 	GNode *asn;
@@ -330,6 +350,67 @@ test_explicit (void)
 }
 
 static void
+test_explicit_encode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestExplicit");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("explicit"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SEXPLICIT, XL (SEXPLICIT));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
+test_universal_decode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+	gchar *value;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestUniversal");
+	g_assert (asn);
+
+	/* Should work */
+	bytes = egg_bytes_new_static (SUNIVERSAL, XL (SUNIVERSAL));
+	if (!egg_asn1x_decode (asn, bytes))
+		g_assert_not_reached ();
+	egg_bytes_unref (bytes);
+
+	value = egg_asn1x_get_string_as_utf8 (asn, NULL);
+	g_assert_cmpstr (value, ==, "universal");
+	g_free (value);
+
+	egg_asn1x_destroy (asn);
+}
+
+static void
+test_universal_encode (void)
+{
+	EggBytes *bytes;
+	GNode *asn;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestUniversal");
+	g_assert (asn);
+
+	if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("universal"), g_free))
+		g_assert_not_reached ();
+
+	bytes = egg_asn1x_encode (asn, NULL);
+	egg_assert_cmpbytes (bytes, ==, SUNIVERSAL, XL (SUNIVERSAL));
+
+	egg_asn1x_destroy (asn);
+	egg_bytes_unref (bytes);
+}
+
+static void
 test_bit_string_decode (void)
 {
 	EggBytes *bytes;
@@ -1278,8 +1359,12 @@ main (int argc, char **argv)
 	g_test_add_func ("/asn1/unsigned", test_unsigned);
 	g_test_add_func ("/asn1/octet_string", test_octet_string);
 	g_test_add_func ("/asn1/generalized_time", test_generalized_time);
-	g_test_add_func ("/asn1/implicit", test_implicit);
-	g_test_add_func ("/asn1/explicit", test_explicit);
+	g_test_add_func ("/asn1/implicit/decode", test_implicit_decode);
+	g_test_add_func ("/asn1/implicit/encode", test_implicit_encode);
+	g_test_add_func ("/asn1/explicit/decode", test_explicit_decode);
+	g_test_add_func ("/asn1/explicit/encode", test_explicit_encode);
+	g_test_add_func ("/asn1/universal/decode", test_universal_decode);
+	g_test_add_func ("/asn1/universal/encode", test_universal_encode);
 	g_test_add_func ("/asn1/bit_string_decode", test_bit_string_decode);
 	g_test_add_func ("/asn1/bit_string_decode_bad", test_bit_string_decode_bad);
 	g_test_add_func ("/asn1/bit_string_decode_ulong", test_bit_string_decode_ulong);
diff --git a/egg/tests/test.asn b/egg/tests/test.asn
index 28cb176..5412a63 100644
--- a/egg/tests/test.asn
+++ b/egg/tests/test.asn
@@ -18,6 +18,8 @@ TestImplicit ::= [5] IMPLICIT OCTET STRING
 
 TestExplicit ::= [5] EXPLICIT OCTET STRING
 
+TestUniversal ::= [UNIVERSAL 5] IMPLICIT OCTET STRING
+
 TestBitString ::= BIT STRING
 
 TestIntegers ::= SEQUENCE {



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