From e186975ed53a897262fb455f5d7a8de842cdbfd2 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 7 Nov 2012 11:14:49 +0100 Subject: [PATCH] egg-asn1x: More complete coverage for ASN.1 tests * Remove or change code that doesn't get executed in normal operation. * Fix a few bugs discovered during the testing. --- egg/egg-asn1x.c | 139 +++--- egg/tests/test-asn1.c | 1237 ++++++++++++++++++++++++++++++++++++++++++++--- egg/tests/test-asn1x.c | 58 +-- egg/tests/test-symkey.c | 4 +- egg/tests/test.asn | 34 +- 5 files changed, 1306 insertions(+), 166 deletions(-) diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c index c35cf1e..4205406 100644 --- a/egg/egg-asn1x.c +++ b/egg/egg-asn1x.c @@ -217,8 +217,7 @@ bytes_new_with_allocator (EggAllocator allocator, if (allocator) { *data = (allocator) (NULL, length + 1); - if (allocator == NULL) - return NULL; + g_return_val_if_fail (*data != NULL, NULL); closure = g_slice_new (AllocatorClosure); closure->allocated = *data; closure->allocator = allocator; @@ -522,6 +521,7 @@ anode_failure (GNode *node, const gchar *failure) g_free (an->failure); an->failure = g_strdup_printf ("%s: %s", prefix, failure); + g_debug ("egg-asn1: %s", an->failure); return FALSE; /* So this can be chained */ } @@ -734,15 +734,12 @@ atlv_parse_length (const guchar *at, g_assert (at != NULL); g_assert (end != NULL); - g_assert (end >= at); + g_assert (end > at); g_assert (off != NULL); *off = 0; n_data = end - at; - if (n_data == 0) - return 0; - /* short form */ if (!(at[0] & 128)) { *off = 1; @@ -834,8 +831,7 @@ atlv_parse_der_tag (guchar cls, end = bytes_get_end (data); g_assert (*at <= end); - if (*at + off + len > end) - return "invalid length of tlv"; + g_return_val_if_fail (*at + off + len <= end, "invalid length of tlv"); if (len < 0 && !(cls & ASN1_CLASS_STRUCTURED)) return "indefinite length on non-structured type"; @@ -992,10 +988,6 @@ anode_decode_sequence_or_set_of (GNode *node, child = node->children; g_return_val_if_fail (child, FALSE); - /* Remove all the other children */ - while (child->next) - anode_destroy (child->next); - for (ctlv = tlv->child, i = 0; ctlv != NULL; ctlv = ctlv->next, i++) { /* Tag must have same tag as top */ @@ -1085,7 +1077,7 @@ anode_decode_primitive (GNode *node, return anode_decode_choice (node, tlv); default: - return anode_failure (node, "primitive value of an unexpected type"); + return anode_failure (node, "primitive value of an unexpected type"); /* UNREACHABLE: tag validation? */ } } @@ -1114,7 +1106,7 @@ anode_decode_structured (GNode *node, return anode_decode_sequence_or_set_of (node, tlv); default: - return anode_failure (node, "structured value of an unexpected type"); + return anode_failure (node, "structured value of an unexpected type"); /* UNREACHABLE: tag validation? */ } } @@ -1454,8 +1446,7 @@ atlv_unparse_to_bytes (Atlv *tlv, g_return_val_if_fail (len != 0, NULL); bytes = bytes_new_with_allocator (allocator, &data, len); - if (data == NULL) - return NULL; + g_return_val_if_fail (bytes != NULL, NULL); at = data; atlv_unparse_der (tlv, &at, data + len); @@ -1498,8 +1489,7 @@ atlv_sort_perform (Atlv *tlv, pairs = NULL; for (ctlv = tlv->child; ctlv != NULL; ctlv = ctlv->next) { bytes = atlv_unparse_to_bytes (ctlv, allocator); - if (bytes == NULL) - break; + g_return_if_fail (bytes != NULL); pair = g_slice_new0 (SortPair); pair->bytes = bytes; @@ -1690,8 +1680,9 @@ anode_build_choice (GNode *node, g_assert (anode_def_type (node) == EGG_ASN1X_CHOICE); child = egg_asn1x_get_choice (node); - if (!child) - return FALSE; + + /* Should have been checked by a previous validate */ + g_return_val_if_fail (child != NULL, NULL); return anode_build_anything (child, want); } @@ -1738,7 +1729,7 @@ anode_build_structured (GNode *node, atlv_free (tlv); return NULL; } - } else { + } else if (!want) { atlv_free (tlv); return NULL; } @@ -1846,10 +1837,9 @@ egg_asn1x_encode (GNode *asn, return NULL; tlv = anode_build_anything (asn, TRUE); - if (tlv == NULL) { - anode_failure (asn, "missing value(s)"); - return NULL; - } + + /* The above validate should cause build not to return NULL */ + g_return_val_if_fail (tlv != NULL, NULL); atlv_sort_perform (tlv, allocator); @@ -2288,8 +2278,8 @@ anode_read_string_struct (GNode *node, } } - if (value && remaining < 0) - return FALSE; + if (value) + g_return_val_if_fail (remaining >= 0, FALSE); return TRUE; } @@ -2308,10 +2298,7 @@ anode_read_string_simple (GNode *node, buf = g_bytes_get_data (data, &len); if (value) { - if (*n_value < len) { - *n_value = len; - return FALSE; - } + g_return_val_if_fail (*n_value >= len, FALSE); memcpy (value, buf, len); } @@ -2332,14 +2319,13 @@ anode_read_boolean (GNode *node, g_assert (value != NULL); buf = g_bytes_get_data (data, &len); - if (len != 1) - return FALSE; + g_return_val_if_fail (len == 1, FALSE); if (buf[0] == 0x00) *value = FALSE; else if (buf[0] == 0xFF) *value = TRUE; else - return FALSE; + g_return_val_if_reached (FALSE); return TRUE; } @@ -2436,7 +2422,7 @@ anode_read_object_id (GNode *node, if (k < len) { if (result) - g_string_free (result, TRUE); + g_string_free (result, TRUE); /* UNREACHABLE: caught by validation */ return FALSE; } @@ -2719,10 +2705,8 @@ egg_asn1x_get_enumerated (GNode *node) if (data == NULL) return 0; - /* TODO: Signed values */ - if (!anode_read_integer_ulong (node, data, &val)) - return 0; + g_return_val_if_reached (0); /* Format that as a string */ if (g_snprintf (buf, sizeof (buf), "%lu", val) < 0) @@ -2835,9 +2819,10 @@ egg_asn1x_get_integer_as_raw (GNode *node) 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; + g_warning ("cannot read integer set with " /* UNREACHABLE: */ + "egg_asn1x_set_integer_as_raw() " /* UNREACHABLE: */ + "via egg_asn1x_get_integer_as_raw()"); /* UNREACHABLE: */ + return NULL; /* UNREACHABLE: unreachable by coverage testing */ } raw = anode_get_value (node); @@ -2866,8 +2851,8 @@ egg_asn1x_get_integer_as_usg (GNode *node) if (!an->guarantee_unsigned) { sign = !!(p[0] & 0x80); if (sign) { - g_warning ("invalid two's complement integer is negative, but expected unsigned"); - return NULL; + g_warning ("invalid two's complement integer"); /* UNREACHABLE: */ + return NULL; /* UNREACHABLE: by coverage testing */ } /* Strip off the extra zero byte that was preventing it from being negative */ @@ -2911,8 +2896,8 @@ egg_asn1x_take_integer_as_raw (GNode *node, sign = !!(p[0] & 0x80); if (sign) { - g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement"); - return; + g_warning ("integer is not two's complement"); /* UNREACHABLE: */ + return; /* UNREACHABLE: unless warning */ } anode_clr_value (node); @@ -3009,8 +2994,7 @@ egg_asn1x_get_any_into_full (GNode *node, /* 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; + g_return_val_if_fail (tlv != NULL, FALSE); } if (!anode_decode_anything (into, tlv)) @@ -3153,16 +3137,14 @@ egg_asn1x_get_string_as_raw (GNode *node, data = anode_get_value (node); if (data != NULL) { if (!anode_read_string_simple (node, data, NULL, &length)) - return NULL; + g_return_val_if_reached (NULL); string = (allocator) (NULL, length + 1); if (string == NULL) - return NULL; + return NULL; /* UNREACHABLE: unless odd allocator */ - if (!anode_read_string_simple (node, data, string, &length)) { - (allocator) (string, 0); - return NULL; - } + if (!anode_read_string_simple (node, data, string, &length)) + g_return_val_if_reached (NULL); /* Courtesy null termination, string must however be validated! */ string[length] = 0; @@ -3177,12 +3159,10 @@ egg_asn1x_get_string_as_raw (GNode *node, string = (allocator) (NULL, length + 1); if (string == NULL) - return NULL; + return NULL; /* UNREACHABLE: unless odd allocator */ - if (!anode_read_string_struct (node, tlv, string, &length)) { - (allocator) (string, 0); - return NULL; - } + if (!anode_read_string_struct (node, tlv, string, &length)) + g_return_val_if_reached (NULL); /* should have failed above */ /* Courtesy null termination, string must however be validated! */ string[length] = 0; @@ -3468,7 +3448,7 @@ egg_asn1x_get_time_as_long (GNode *node) return -1; if (!anode_read_time (node, data, &when, &time)) - return -1; + g_return_val_if_reached (-1); /* already validated */ return time; } @@ -3500,7 +3480,7 @@ egg_asn1x_get_time_as_date (GNode *node, return FALSE; if (!anode_read_time (node, data, &when, &time)) - return FALSE; + g_return_val_if_reached (FALSE); /* already validated */ g_date_set_dmy (date, when.tm_mday, when.tm_mon + 1, when.tm_year + 1900); return TRUE; @@ -3520,7 +3500,7 @@ egg_asn1x_get_oid_as_string (GNode *node) return NULL; if (!anode_read_object_id (node, data, &oid)) - return NULL; + g_return_val_if_reached (NULL); /* should have been validated */ return oid; } @@ -3731,16 +3711,13 @@ anode_validate_enumerated (GNode *node, g_assert (value != NULL); - if (!anode_validate_integer (node, value)) - return FALSE; - buf = g_bytes_get_data (value, &length); - g_assert (length > 0); /* Checked above */ /* Enumerated must be positive */ - if (buf[0] & 0x80) + if (length > 0 && (buf[0] & 0x80)) return anode_failure (node, "enumerated must be positive"); - return TRUE; + + return anode_validate_integer (node, value); } static gboolean @@ -3778,7 +3755,7 @@ anode_validate_string (GNode *node, gsize length; if (!anode_read_string_simple (node, value, NULL, &length)) - return anode_failure (node, "string content is invalid"); + g_return_val_if_reached (FALSE); return anode_validate_size (node, (gulong)length); } @@ -3839,12 +3816,16 @@ anode_validate_sequence_or_set (GNode *node, { GNode *child; + /* If this is optional, and has no values, then that's all good */ + if (anode_def_flags (node) & FLAG_OPTION) { + if (!egg_asn1x_have (node)) + return TRUE; + } + /* All of the children must validate properly */ for (child = node->children; child; child = child->next) { - if (egg_asn1x_have (child)) { - if (!anode_validate_anything (child, strict)) - return FALSE; - } + if (!anode_validate_anything (child, strict)) + return FALSE; } return TRUE; @@ -3868,6 +3849,9 @@ anode_validate_sequence_or_set_of (GNode *node, } } + if (count == 0 && anode_def_flags (node) & FLAG_OPTION) + return TRUE; + return anode_validate_size (node, count); } @@ -3878,8 +3862,10 @@ anode_validate_anything (GNode *node, GBytes *value; Atlv *tlv; gint type; + gint flags; type = anode_def_type (node); + flags = anode_def_flags (node); /* Handle these specially */ switch (type) { @@ -3911,13 +3897,12 @@ anode_validate_anything (GNode *node, case EGG_ASN1X_BIT_STRING: return anode_validate_bit_string (node, value); case EGG_ASN1X_OCTET_STRING: + case EGG_ASN1X_GENERALSTRING: 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: @@ -3934,13 +3919,13 @@ anode_validate_anything (GNode *node, case EGG_ASN1X_OCTET_STRING: return TRUE; default: - break; + break; /* UNREACHABLE: fix compiler warning */ } } - if (anode_def_flags (node) & FLAG_OPTION) + if (flags & FLAG_OPTION) return TRUE; - if (anode_def_flags (node) & FLAG_DEFAULT) + if (flags & FLAG_DEFAULT) return TRUE; return anode_failure (node, "missing value"); } diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c index 09645d6..3bd43a5 100644 --- a/egg/tests/test-asn1.c +++ b/egg/tests/test-asn1.c @@ -104,6 +104,54 @@ test_boolean (void) } static void +test_boolean_decode_bad (void) +{ + const gchar BOOLEAN_INVALID_LENGTH[] = "\x01\x02\x00\x00"; + const gchar BOOLEAN_BAD_VALUE[] = "\x01\x01\x05"; + + GBytes *bytes; + GNode *asn; + gboolean ret; + + asn = egg_asn1x_create (test_asn1_tab, "TestBoolean"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (BOOLEAN_INVALID_LENGTH, XL (BOOLEAN_INVALID_LENGTH)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "invalid length boolean") != NULL); + g_bytes_unref (bytes); + + bytes = g_bytes_new_static (BOOLEAN_BAD_VALUE, XL (BOOLEAN_BAD_VALUE)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "boolean must be true or false") != NULL); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_boolean_default (void) +{ + GNode *asn; + GBytes *bytes; + + const gchar BOOLEAN[] = "\x30\x00"; + + asn = egg_asn1x_create (test_asn1_tab, "TestBooleanDefault"); + /* This is equal to the default value, and shouldn't be included */ + egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE); + + bytes = egg_asn1x_encode (asn, NULL); + egg_asn1x_assert (bytes != NULL, asn); + egg_assert_cmpbytes (bytes, ==, BOOLEAN, XL (BOOLEAN)); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void test_null (void) { GNode *asn; @@ -161,6 +209,27 @@ test_integer (void) } static void +test_integer_zero_length (void) +{ + const gchar INTEGER_EMPTY[] = "\x02\x00"; + + GBytes *bytes; + GNode *asn; + gboolean ret; + + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (INTEGER_EMPTY, XL (INTEGER_EMPTY)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "zero length integer") != NULL); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void test_unsigned (void) { GNode *asn; @@ -216,6 +285,125 @@ test_unsigned (void) } static void +test_unsigned_not_set (void) +{ + GNode *asn; + GBytes *bytes; + + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn); + + bytes = egg_asn1x_get_integer_as_usg (asn); + g_assert (bytes == NULL); + + egg_asn1x_destroy (asn); +} + +static void +test_unsigned_default (void) +{ + GNode *asn; + GBytes *bytes; + + const gchar INTEGERS[] = "\x30\x06\x02\x01\x01\x02\x01\x02"; + + asn = egg_asn1x_create (test_asn1_tab, "TestIntegers"); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 1); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 2); + /* This is equal to the default value, and shouldn't be included */ + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 8888); + + bytes = egg_asn1x_encode (asn, NULL); + egg_assert_cmpbytes (bytes, ==, INTEGERS, XL (INTEGERS)); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_unsigned_constant (void) +{ + gulong value; + GNode *asn; + + /* const gchar SEQ[] = "\x30\x00"; */ + + asn = egg_asn1x_create (test_asn1_tab, "TestConstant"); + if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &value)) + g_assert_not_reached (); + g_assert_cmpint (value, ==, 3); + + egg_asn1x_destroy (asn); +} + +static void +test_unsigned_zero (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\x02\x01\x00"; + + /* No bits set in 0 but should still be 1 byte */ + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + egg_asn1x_set_integer_as_ulong (asn, 0); + + bytes = egg_asn1x_encode (asn, NULL); + egg_asn1x_assert (bytes != NULL, asn); + egg_assert_cmpbytes (bytes, ==, DER, XL (DER)); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_integer_raw (void) +{ + GNode *asn; + GBytes *bytes; + + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("\x01\x02\x03", 3); + egg_asn1x_set_integer_as_raw (asn, bytes); + g_bytes_unref (bytes); + + bytes = egg_asn1x_encode (asn, NULL); + egg_assert_cmpbytes (bytes, ==, "\x02\x03\x01\x02\x03", 5); + g_bytes_unref (bytes); + + bytes = egg_asn1x_get_integer_as_raw (asn); + egg_assert_cmpbytes (bytes, ==, "\x01\x02\x03", 3); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_integer_raw_not_twos_complement (void) +{ + GNode *asn; + GBytes *bytes; + + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("\x81\x02\x03", 3); + + if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) { + egg_asn1x_set_integer_as_raw (asn, bytes); /* UNREACHABLE: */ + exit(0); /* UNREACHABLE: for code coverage */ + } + + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*not two's complement*"); + + g_bytes_unref (bytes); + egg_asn1x_destroy (asn); +} + +static void test_octet_string (void) { GNode *asn; @@ -251,6 +439,131 @@ test_octet_string (void) } static void +test_octet_string_set_bad_utf8 (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestOctetString"); + g_assert (asn); + + if (egg_asn1x_set_string_as_utf8 (asn, "\xFF\xFA", NULL)) + g_assert_not_reached (); + + /* Shouldn't succeed */ + if (egg_asn1x_get_string_as_utf8 (asn, NULL)) + g_assert_not_reached (); + + egg_asn1x_destroy (asn); +} + +static void +test_octet_string_bmp_as_utf8 (void) +{ + GBytes *bytes; + GNode *asn; + gchar *data; + + const gchar SFUER[] = "\x04\x06""\x00\x46\x00\xfc\x00\x72"; + + bytes = g_bytes_new_static (SFUER, XL (SFUER)); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + data = egg_asn1x_get_bmpstring_as_utf8 (asn); + g_assert_cmpstr (data, ==, "F\303\274r"); + + g_free (data); + egg_asn1x_destroy (asn); +} + +static void +test_octet_string_get_as_bytes (void) +{ + GBytes *bytes; + GNode *asn; + + bytes = g_bytes_new_static (SFARNSWORTH, XL (SFARNSWORTH)); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_assert (asn != NULL); + g_bytes_unref (bytes); + + bytes = egg_asn1x_get_string_as_bytes (asn); + g_assert (bytes != NULL); + egg_assert_cmpbytes (bytes, ==, "farnsworth", 10); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_octet_string_set_as_bytes (void) +{ + GBytes *bytes; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestOctetString"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("farnsworth", 10); + egg_asn1x_set_string_as_bytes (asn, bytes); + g_bytes_unref (bytes); + + bytes = egg_asn1x_encode (asn, NULL); + g_assert (bytes != NULL); + egg_assert_cmpbytes (bytes, ==, SFARNSWORTH, XL (SFARNSWORTH)); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_octet_string_structured (void) +{ + GBytes *bytes; + GNode *asn; + guchar *string; + gsize n_string = 0; + + const gchar STRUCTURED[] = "\x24\x0c" + "\x04\x04""blah" + "\x04\x04""blah"; + + bytes = g_bytes_new_static (STRUCTURED, XL (STRUCTURED)); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_bytes_unref (bytes); + + string = egg_asn1x_get_string_as_raw (asn, NULL, &n_string); + g_assert_cmpstr ((gchar *)string, ==, "blahblah"); + g_assert_cmpint (n_string, ==, 8); + g_free (string); + + egg_asn1x_destroy (asn); +} + +static void +test_octet_string_structured_bad (void) +{ + GBytes *bytes; + GNode *asn; + guchar *string; + gsize n_string = 0; + + const gchar STRUCTURED[] = "\x24\x0c" + "\x24\x04\x04\02""bl" + "\x04\x04""blah"; + + bytes = g_bytes_new_static (STRUCTURED, XL (STRUCTURED)); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_bytes_unref (bytes); + + string = egg_asn1x_get_string_as_raw (asn, NULL, &n_string); + g_assert (string == NULL); + + egg_asn1x_destroy (asn); +} + +static void test_generalized_time (void) { GBytes *bytes; @@ -284,6 +597,19 @@ test_generalized_time (void) } static void +test_time_get_missing (void) +{ + GDate date; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestGeneralized"); + if (egg_asn1x_get_time_as_date (asn, &date)) + g_assert_not_reached (); + g_assert (egg_asn1x_get_time_as_long (asn) == -1); + egg_asn1x_destroy (asn); +} + +static void test_implicit_encode (void) { GBytes *bytes; @@ -348,6 +674,68 @@ test_explicit_decode (void) } static void +test_explicit_no_context_specific (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\x45\x0A\x04\x08""explicit"; + + asn = egg_asn1x_create (test_asn1_tab, "TestExplicit"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "missing context specific tag")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_explicit_no_context_child (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\xA5\x00"; + + asn = egg_asn1x_create (test_asn1_tab, "TestExplicit"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "missing context specific child")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_explicit_extra_context_child (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\xA5\x14" + "\x04\x08""explicit" + "\x04\x08""explicit"; + + asn = egg_asn1x_create (test_asn1_tab, "TestExplicit"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "multiple context specific children")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void test_explicit_encode (void) { GBytes *bytes; @@ -373,113 +761,202 @@ test_universal_decode (void) GNode *asn; gchar *value; - asn = egg_asn1x_create (test_asn1_tab, "TestUniversal"); + asn = egg_asn1x_create (test_asn1_tab, "TestUniversal"); + g_assert (asn); + + /* Should work */ + bytes = g_bytes_new_static (SUNIVERSAL, XL (SUNIVERSAL)); + if (!egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_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) +{ + GBytes *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); + g_bytes_unref (bytes); +} + +static void +test_bit_string_decode (void) +{ + GBytes *bytes; + GNode *asn; + GBytes *bits; + guint n_bits; + const guchar *data; + + asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); + g_assert (asn); + + g_assert_cmpint (EGG_ASN1X_BIT_STRING, ==, egg_asn1x_type (asn)); + + /* Should work */ + bytes = g_bytes_new_static (BITS_TEST, XL (BITS_TEST)); + if (!egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_bytes_unref (bytes); + + bits = egg_asn1x_get_bits_as_raw (asn, &n_bits); + g_assert (bits != NULL); + g_assert_cmpuint (n_bits, ==, 18); + data = g_bytes_get_data (bits, NULL); + g_assert_cmpint (data[0], ==, 0x6e); + g_assert_cmpint (data[1], ==, 0x5d); + g_assert_cmpint (data[2], ==, 0xc0); + + g_bytes_unref (bits); + egg_asn1x_destroy (asn); +} + +static void +test_bit_string_decode_bad (void) +{ + GBytes *bytes; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); + g_assert (asn); + + /* Should not work */ + bytes = g_bytes_new_static (BITS_BAD, XL (BITS_BAD)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_bit_string_decode_ulong (void) +{ + GBytes *bytes; + GNode *asn; + gulong bits; + guint n_bits; + + asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); g_assert (asn); /* Should work */ - bytes = g_bytes_new_static (SUNIVERSAL, XL (SUNIVERSAL)); + bytes = g_bytes_new_static (BITS_TEST, XL (BITS_TEST)); if (!egg_asn1x_decode (asn, bytes)) g_assert_not_reached (); g_bytes_unref (bytes); - value = egg_asn1x_get_string_as_utf8 (asn, NULL); - g_assert_cmpstr (value, ==, "universal"); - g_free (value); + if (!egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits)) + g_assert_not_reached (); + + g_assert_cmpuint (n_bits, ==, 18); + g_assert_cmphex (bits, ==, 0x1b977); egg_asn1x_destroy (asn); } static void -test_universal_encode (void) +test_bit_string_ulong_too_long (void) { GBytes *bytes; GNode *asn; + gulong bits; + guint n_bits; - asn = egg_asn1x_create (test_asn1_tab, "TestUniversal"); + const gchar BITS_TEST[] = "\x03\x20\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; + + asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); g_assert (asn); - if (!egg_asn1x_set_string_as_utf8 (asn, g_strdup ("universal"), g_free)) + /* Should work */ + + bytes = g_bytes_new_static (BITS_TEST, XL (BITS_TEST)); + if (!egg_asn1x_decode (asn, bytes)) g_assert_not_reached (); + g_bytes_unref (bytes); - bytes = egg_asn1x_encode (asn, NULL); - egg_assert_cmpbytes (bytes, ==, SUNIVERSAL, XL (SUNIVERSAL)); + if (egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits)) + g_assert_not_reached (); egg_asn1x_destroy (asn); - g_bytes_unref (bytes); } static void -test_bit_string_decode (void) +test_bit_string_get_not_set (void) { - GBytes *bytes; GNode *asn; - GBytes *bits; + gulong bits; guint n_bits; - const guchar *data; asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); - g_assert (asn); - g_assert_cmpint (EGG_ASN1X_BIT_STRING, ==, egg_asn1x_type (asn)); - - /* Should work */ - bytes = g_bytes_new_static (BITS_TEST, XL (BITS_TEST)); - if (!egg_asn1x_decode (asn, bytes)) + if (egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits)) g_assert_not_reached (); - g_bytes_unref (bytes); - - bits = egg_asn1x_get_bits_as_raw (asn, &n_bits); - g_assert (bits != NULL); - g_assert_cmpuint (n_bits, ==, 18); - data = g_bytes_get_data (bits, NULL); - g_assert_cmpint (data[0], ==, 0x6e); - g_assert_cmpint (data[1], ==, 0x5d); - g_assert_cmpint (data[2], ==, 0xc0); + g_assert (egg_asn1x_get_bits_as_raw (asn, &n_bits) == NULL); - g_bytes_unref (bits); egg_asn1x_destroy (asn); } static void -test_bit_string_decode_bad (void) +test_bit_string_invalid_length (void) { GBytes *bytes; GNode *asn; + const gchar DER[] = "\x03\x00"; + asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); g_assert (asn); - /* Should not work */ - bytes = g_bytes_new_static (BITS_BAD, XL (BITS_BAD)); + /* Should work */ + + bytes = g_bytes_new_static (DER, XL (DER)); if (egg_asn1x_decode (asn, bytes)) g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "invalid length bit string")); g_bytes_unref (bytes); egg_asn1x_destroy (asn); } static void -test_bit_string_decode_ulong (void) +test_bit_string_invalid_empty (void) { GBytes *bytes; GNode *asn; - gulong bits; - guint n_bits; + + const gchar DER[] = "\x03\x01\x09"; asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); g_assert (asn); /* Should work */ - bytes = g_bytes_new_static (BITS_TEST, XL (BITS_TEST)); - if (!egg_asn1x_decode (asn, bytes)) - g_assert_not_reached (); - g_bytes_unref (bytes); - if (!egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits)) + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) g_assert_not_reached (); - - g_assert_cmpuint (n_bits, ==, 18); - g_assert_cmphex (bits, ==, 0x1b977); + g_assert (strstr (egg_asn1x_message (asn), "invalid number of empty bits")); + g_bytes_unref (bytes); egg_asn1x_destroy (asn); } @@ -491,6 +968,7 @@ test_bit_string_encode_decode (void) GNode *asn; guchar bits[] = { 0x5d, 0x6e, 0x83 }; GBytes *check; + GBytes *bytes; const guchar *ch; guint n_bits = 17; guint n_check; @@ -498,7 +976,9 @@ test_bit_string_encode_decode (void) asn = egg_asn1x_create (test_asn1_tab, "TestBitString"); g_assert (asn); - egg_asn1x_take_bits_as_raw (asn, g_bytes_new (bits, 3), n_bits); + bytes = g_bytes_new (bits, 3); + egg_asn1x_set_bits_as_raw (asn, bytes, n_bits); + g_bytes_unref (bytes); data = egg_asn1x_encode (asn, NULL); g_assert (data); @@ -603,7 +1083,7 @@ test_is_freed (gpointer unused) } static void -test_any_set_raw (void) +test_any_raw (void) { GBytes *bytes; GNode *asn, *node; @@ -632,18 +1112,22 @@ test_any_set_raw (void) egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING)); check = egg_asn1x_get_element_raw (node); - g_assert (check); + g_assert (check != NULL); + egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH)); + g_bytes_unref (check); + check = egg_asn1x_get_any_raw (node, NULL); + g_assert (check != NULL); egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH)); + g_bytes_unref (check); g_bytes_unref (data); - g_bytes_unref (check); egg_asn1x_destroy (asn); g_assert (is_freed); } static void -test_any_set_raw_explicit (void) +test_any_raw_explicit (void) { GBytes *bytes; GNode *asn, *node; @@ -675,6 +1159,161 @@ test_any_set_raw_explicit (void) } static void +test_any_raw_invalid (void) +{ + GBytes *bytes; + GNode *asn, *node; + + const gchar TRUNCATED[] = "\x04\x0A""farns"; + + asn = egg_asn1x_create (test_asn1_tab, "TestAnySeq"); + g_assert (asn != NULL); + + node = egg_asn1x_node (asn, "contents", NULL); + g_assert (node != NULL); + + bytes = g_bytes_new_static (TRUNCATED, XL (TRUNCATED)); + if (egg_asn1x_set_any_raw (node, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (node), "content is not encoded properly") != NULL); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_any_raw_not_set (void) +{ + GBytes *check; + GNode *asn, *node; + + asn = egg_asn1x_create (test_asn1_tab, "TestAnySeq"); + g_assert (asn != NULL); + + node = egg_asn1x_node (asn, "contents", NULL); + g_assert (node != NULL); + + check = egg_asn1x_get_any_raw (node, NULL); + g_assert (check == NULL); + + egg_asn1x_destroy (asn); +} + +static void +test_any_into (void) +{ + GBytes *bytes; + GNode *asn, *node; + GNode *part; + GBytes *data; + GBytes *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 != NULL); + + is_freed = FALSE; + node = egg_asn1x_node (asn, "contents", NULL); + g_assert (node); + + bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), + test_is_freed, NULL); + part = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_assert (part != NULL); + g_bytes_unref (bytes); + + egg_asn1x_set_any_from (node, part); + egg_asn1x_destroy (part); + + data = egg_asn1x_encode (asn, NULL); + g_assert (data != NULL); + egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING)); + + part = egg_asn1x_create (test_asn1_tab, "TestOctetString"); + if (!egg_asn1x_get_any_into (node, part)) + g_assert_not_reached (); + + check = egg_asn1x_encode (part, NULL); + egg_asn1x_destroy (part); + g_assert (check != NULL); + egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH)); + g_bytes_unref (check); + + g_bytes_unref (data); + egg_asn1x_destroy (asn); + g_assert (is_freed); +} + +static void +test_any_into_explicit (void) +{ + GBytes *bytes; + GNode *asn, *node; + GNode *part; + GBytes *data; + GBytes *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 != NULL); + + is_freed = FALSE; + node = egg_asn1x_node (asn, "contents", NULL); + g_assert (node); + + bytes = g_bytes_new_with_free_func (SFARNSWORTH, XL (SFARNSWORTH), + test_is_freed, NULL); + part = egg_asn1x_create_and_decode (test_asn1_tab, "TestOctetString", bytes); + g_assert (part != NULL); + g_bytes_unref (bytes); + + egg_asn1x_set_any_from (node, part); + egg_asn1x_destroy (part); + + data = egg_asn1x_encode (asn, NULL); + g_assert (data != NULL); + egg_assert_cmpbytes (data, ==, SEQ_ENCODING, XL (SEQ_ENCODING)); + + part = egg_asn1x_create (test_asn1_tab, "TestOctetString"); + if (!egg_asn1x_get_any_into (node, part)) + g_assert_not_reached (); + + check = egg_asn1x_encode (part, NULL); + egg_asn1x_destroy (part); + g_assert (check != NULL); + egg_assert_cmpbytes (check, ==, SFARNSWORTH, XL (SFARNSWORTH)); + g_bytes_unref (check); + + g_bytes_unref (data); + egg_asn1x_destroy (asn); + g_assert (is_freed); +} + +static void +test_any_into_explicit_not_set (void) +{ + GNode *asn, *node; + GNode *part; + + asn = egg_asn1x_create (test_asn1_tab, "TestAnyExp"); + g_assert (asn != NULL); + + node = egg_asn1x_node (asn, "contents", NULL); + g_assert (node); + + part = egg_asn1x_create (test_asn1_tab, "TestOctetString"); + if (egg_asn1x_get_any_into (node, part)) + g_assert_not_reached (); + + egg_asn1x_destroy (part); + egg_asn1x_destroy (asn); +} + +static void test_choice_not_chosen (void) { GBytes *bytes; @@ -756,10 +1395,118 @@ test_any_choice_set_raw_short_tag (void) } static void -test_any_choice_set_raw_long_tag (void) +test_any_choice_set_raw_long_tag (void) +{ + const gchar ENCODING[] = "\xBF\x1F\x0C\x04\x0A""farnsworth"; + perform_asn1_any_choice_set_raw ("choiceLongTag", ENCODING, XL (ENCODING)); +} + +static void +test_seq_of_any (void) +{ + GNode *asn; + GNode *integer; + GBytes *bytes; + gboolean ret; + gulong value; + + const gchar DER[] = "\x30\x06" + "\x02\x01\x88" + "\x02\x01\x33"; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOfAny"); + g_assert (asn != NULL); + + egg_asn1x_append (asn); + egg_asn1x_append (asn); + + bytes = g_bytes_new_static (DER, XL (DER)); + ret = egg_asn1x_decode (asn, bytes); + egg_asn1x_assert (ret == TRUE, asn); + g_bytes_unref (bytes); + + integer = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (integer != NULL); + + ret = egg_asn1x_get_any_into (egg_asn1x_node (asn, 1, NULL), integer); + egg_asn1x_assert (ret == TRUE, integer); + if (!egg_asn1x_get_integer_as_ulong (integer, &value)) + g_assert_not_reached (); + g_assert_cmpint (value, ==, 0x88); + + ret = egg_asn1x_get_any_into (egg_asn1x_node (asn, 2, NULL), integer); + egg_asn1x_assert (ret == TRUE, integer); + if (!egg_asn1x_get_integer_as_ulong (integer, &value)) + g_assert_not_reached (); + g_assert_cmpint (value, ==, 0x33); + + egg_asn1x_destroy (integer); + egg_asn1x_destroy (asn); +} + +static void +test_seq_of_invalid (void) +{ + GNode *asn; + GBytes *bytes; + + const gchar DER[] = "\x30\x05" + "\x04\x00" + "\x02\x01\x88"; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOf"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_seq_of_different (void) +{ + GNode *asn; + GBytes *bytes; + + const gchar DER[] = "\x30\x05" + "\x02\x01\x88" + "\x04\x00"; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOf"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_set_order (void) { - const gchar ENCODING[] = "\xBF\x1F\x0C\x04\x0A""farnsworth"; - perform_asn1_any_choice_set_raw ("choiceLongTag", ENCODING, XL (ENCODING)); + GNode *asn; + GBytes *bytes; + + const gchar DER[] = "\x31\x0f" + "\xA2\x03\x02\x01\x99" + "\xA1\x03\x02\x01\x88" + "\xA3\x03\x02\x01\x88"; + + asn = egg_asn1x_create (test_asn1_tab, "TestSet"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "content must be in ascending order")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); } static void @@ -918,6 +1665,74 @@ test_enumerated (void) egg_asn1x_destroy (asn); } +static void +test_enumerated_decode_bad (void) +{ + const gchar ENUM_NEGATIVE[] = "\x0A\x01\x85"; + + GBytes *bytes; + GNode *asn; + gboolean ret; + + asn = egg_asn1x_create (test_asn1_tab, "TestEnumerated"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (ENUM_NEGATIVE, XL (ENUM_NEGATIVE)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "enumerated must be positive") != NULL); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_enumerated_not_in_list (void) +{ + const gchar ENUM_OTHER[] = "\x0A\x01\x08"; + const gchar ENUM_LARGE[] = "\x0A\x20\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; + + GBytes *bytes; + GNode *asn; + gboolean ret; + + asn = egg_asn1x_create (test_asn1_tab, "TestEnumerated"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (ENUM_OTHER, XL (ENUM_OTHER)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "not part of list") != NULL); + g_bytes_unref (bytes); + + bytes = g_bytes_new_static (ENUM_LARGE, XL (ENUM_LARGE)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "not part of list") != NULL); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_enumerated_not_set (void) +{ + GNode *asn; + GQuark value; + + asn = egg_asn1x_create (test_asn1_tab, "TestEnumerated"); + g_assert (asn != NULL); + + value = egg_asn1x_get_enumerated (asn); + g_assert (value == 0); + + egg_asn1x_destroy (asn); +} + + typedef struct { GNode *asn1; guchar *data; @@ -1148,7 +1963,7 @@ test_read_element (Test* test, gconstpointer unused) } static void -test_oid (Test* test, gconstpointer unused) +test_oid (void) { GBytes *buffer; GNode *asn = NULL; @@ -1190,6 +2005,57 @@ test_oid (Test* test, gconstpointer unused) egg_asn1x_destroy (asn); } +static void +test_oid_set_invalid (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestOid"); + g_assert ("asn test structure is null" && asn != NULL); + + if (egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "oid", NULL), "abcd")) + g_assert_not_reached (); + + egg_asn1x_destroy (asn); +} + +static void +test_oid_decode_bad (void) +{ + GBytes *bytes; + GNode *asn; + gboolean ret; + + /* Has invalid leading integer in oid value */ + const gchar INVALID_OID[] = "\x30\x07\x06\x05\x2b\x80\x83\x82\x1a"; + + asn = egg_asn1x_create (test_asn1_tab, "TestOid"); + g_assert ("asn test structure is null" && asn != NULL); + + bytes = g_bytes_new_static (INVALID_OID, XL (INVALID_OID)); + ret = egg_asn1x_decode (asn, bytes); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "object id encoding is invalid") != NULL); + + g_bytes_unref (bytes); + egg_asn1x_destroy (asn); +} + +static void +test_oid_get_no_value (void) +{ + GNode *asn; + gchar *oid; + + asn = egg_asn1x_create (test_asn1_tab, "TestOid"); + g_assert ("asn test structure is null" && asn != NULL); + + oid = egg_asn1x_get_oid_as_string (egg_asn1x_node (asn, "oid", NULL)); + g_assert (oid == NULL); + + egg_asn1x_destroy (asn); +} + typedef struct _TimeTestData { gchar *value; time_t ref; @@ -1376,21 +2242,252 @@ test_nested_unexpected (void) egg_asn1x_destroy (asn); } +static void +test_create_and_decode_invalid (void) +{ + GBytes *bytes; + GNode *asn; + + bytes = g_bytes_new_static ("", 0); + asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestData", bytes); + g_assert (asn == NULL); + g_bytes_unref (bytes); +} + +static void +test_decode_extra (void) +{ + GBytes *bytes; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOf"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("\x30\x00\x11", 3); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "extra unexpected trailing data")); + g_bytes_unref (bytes); + egg_asn1x_destroy (asn); +} + +static void +test_decode_nested_short (void) +{ + GBytes *bytes; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOfAny"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("\x30\x02\xA5\x08", 4); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "content is not encoded properly")); + g_bytes_unref (bytes); + + bytes = g_bytes_new_static ("\x30\x04\x30\x02\xA5\x08", 6); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "content is not encoded properly")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_decode_indefinite_primitive (void) +{ + GBytes *bytes; + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static ("\x04\x80\x04\x01\x55\x00\x00", 7); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "indefinite length on non-structured type")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_decode_invalid_long_length (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\x04\xA0" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"; + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "content is not encoded properly")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_decode_truncated_at_tag (void) +{ + GBytes *bytes; + GNode *asn; + + const gchar DER[] = "\x04"; + asn = egg_asn1x_create (test_asn1_tab, "TestInteger"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + if (egg_asn1x_decode (asn, bytes)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "content is not encoded properly")); + g_bytes_unref (bytes); + + egg_asn1x_destroy (asn); +} + +static void +test_decode_long_tag (void) +{ + GBytes *bytes; + GNode *asn; + gboolean ret; + + const gchar DER[] = "\xbf\x89\x52\x03\x04\x01\x33"; + + asn = egg_asn1x_create (test_asn1_tab, "TestTagLong"); + g_assert (asn != NULL); + + bytes = g_bytes_new_static (DER, XL (DER)); + ret = egg_asn1x_decode (asn, bytes); + egg_asn1x_assert (ret == TRUE, asn); + + g_bytes_unref (bytes); + egg_asn1x_destroy (asn); + +} + +static void +test_create_quark (void) +{ + GNode *asn; + + asn = egg_asn1x_create_quark (test_asn1_tab, g_quark_from_static_string ("1.5.13")); + g_assert (asn != NULL); + g_assert_cmpstr (egg_asn1x_name (asn), ==, "TestIntegers"); +} + +static void +test_validate_default (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq"); + /* We leave first boolean field empty */ + egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean2", NULL), TRUE); + if (!egg_asn1x_validate (asn, TRUE)) + g_assert_not_reached (); + egg_asn1x_destroy (asn); +} + +static void +test_validate_missing (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq"); + /* No fields set */ + if (egg_asn1x_validate (asn, TRUE)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "missing value") != NULL); + egg_asn1x_destroy (asn); +} + +static void +test_validate_seq_of_child_invalid (void) +{ + GNode *asn; + GNode *child; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOfSeq"); + child = egg_asn1x_append (asn); + egg_asn1x_set_integer_as_ulong (egg_asn1x_node (child, "uint1", NULL), 5); + /* We didn't set uint2 or uint3 so the child is invalid */ + if (egg_asn1x_validate (asn, TRUE)) + g_assert_not_reached (); + g_assert (strstr (egg_asn1x_message (asn), "missing value") != NULL); + egg_asn1x_destroy (asn); + +} + +static void +test_validate_optional_seq (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestSeqOptional"); + if (!egg_asn1x_validate (asn, TRUE)) + g_assert_not_reached (); + egg_asn1x_destroy (asn); +} + +static void +test_element_get_not_set (void) +{ + GNode *asn; + + asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq"); + g_assert (egg_asn1x_get_element_raw (asn) == NULL); + egg_asn1x_destroy (asn); +} + int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); + g_test_add_func ("/asn1/decode/extra", test_decode_extra); + g_test_add_func ("/asn1/decode/nested-short", test_decode_nested_short); + g_test_add_func ("/asn1/decode/indefinite-primitive", test_decode_indefinite_primitive); + g_test_add_func ("/asn1/decode/invalid-long-length", test_decode_invalid_long_length); + g_test_add_func ("/asn1/decode/truncated-at-tag", test_decode_truncated_at_tag); + g_test_add_func ("/asn1/decode/decode-long-tag", test_decode_long_tag); g_test_add_func ("/asn1/boolean", test_boolean); + g_test_add_func ("/asn1/boolean-bad", test_boolean_decode_bad); + g_test_add_func ("/asn1/boolean-default", test_boolean_default); g_test_add_func ("/asn1/null", test_null); g_test_add_func ("/asn1/integer", test_integer); + g_test_add_func ("/asn1/integer-zero-length", test_integer_zero_length); + g_test_add_func ("/asn1/integer/raw", test_integer_raw); + g_test_add_func ("/asn1/integer/raw-not-twos-complement", test_integer_raw_not_twos_complement); g_test_add_func ("/asn1/unsigned", test_unsigned); + g_test_add_func ("/asn1/unsigned/not-set", test_unsigned_not_set); + g_test_add_func ("/asn1/unsigned/default", test_unsigned_default); + g_test_add_func ("/asn1/unsigned/constant", test_unsigned_constant); + g_test_add_func ("/asn1/unsigned/zero", test_unsigned_zero); g_test_add_func ("/asn1/octet_string", test_octet_string); + g_test_add_func ("/asn1/octet-string/set-bad-utf8", test_octet_string_set_bad_utf8); + g_test_add_func ("/asn1/octet-string/bmp-as-utf8", test_octet_string_bmp_as_utf8); + g_test_add_func ("/asn1/octet-string/get-as-bytes", test_octet_string_get_as_bytes); + g_test_add_func ("/asn1/octet-string/set-as-bytes", test_octet_string_set_as_bytes); + g_test_add_func ("/asn1/octet-string/structured", test_octet_string_structured); + g_test_add_func ("/asn1/octet-string/structured-bad", test_octet_string_structured_bad); g_test_add_func ("/asn1/generalized_time", test_generalized_time); + g_test_add_func ("/asn1/time-get-missing", test_time_get_missing); 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/explicit/no-context-specific", test_explicit_no_context_specific); + g_test_add_func ("/asn1/explicit/no-context-child", test_explicit_no_context_child); + g_test_add_func ("/asn1/explicit/extra-context-child", test_explicit_extra_context_child); 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); @@ -1399,26 +2496,52 @@ main (int argc, char **argv) g_test_add_func ("/asn1/bit_string_encode_decode", test_bit_string_encode_decode); g_test_add_func ("/asn1/bit_string_encode_decode_ulong", test_bit_string_encode_decode_ulong); g_test_add_func ("/asn1/bit_string_encode_decode_zero", test_bit_string_encode_decode_zero); + g_test_add_func ("/asn1/bit-string/ulong-too-long", test_bit_string_ulong_too_long); + g_test_add_func ("/asn1/bit-string/get-not-set", test_bit_string_get_not_set); + g_test_add_func ("/asn1/bit-string/invalid-length", test_bit_string_invalid_length); + g_test_add_func ("/asn1/bit-string/invalid-empty", test_bit_string_invalid_empty); + g_test_add_func ("/asn1/oid", test_oid); + g_test_add_func ("/asn1/oid/set-invalid", test_oid_set_invalid); + g_test_add_func ("/asn1/oid/get-no-value", test_oid_get_no_value); + g_test_add_func ("/asn1/oid/decode-bad", test_oid_decode_bad); g_test_add_func ("/asn1/have", test_have); - g_test_add_func ("/asn1/any_set_raw", test_any_set_raw); - g_test_add_func ("/asn1/any_set_raw_explicit", test_any_set_raw_explicit); + g_test_add_func ("/asn1/any-raw", test_any_raw); + g_test_add_func ("/asn1/any-raw/explicit", test_any_raw_explicit); + g_test_add_func ("/asn1/any-raw/invalid", test_any_raw_invalid); + g_test_add_func ("/asn1/any-raw/not-set", test_any_raw_not_set); + g_test_add_func ("/asn1/any-into", test_any_into); + g_test_add_func ("/asn1/any-into/explicit", test_any_into_explicit); + g_test_add_func ("/asn1/any-into/explicit-not-set", test_any_into_explicit_not_set); g_test_add_func ("/asn1/choice_not_chosen", test_choice_not_chosen); g_test_add_func ("/asn1/any_choice_set_raw_short_tag", test_any_choice_set_raw_short_tag); g_test_add_func ("/asn1/any_choice_set_raw_long_tag", test_any_choice_set_raw_long_tag); + g_test_add_func ("/asn1/seq-of-any", test_seq_of_any);\ + g_test_add_func ("/asn1/seq-of-invalid", test_seq_of_invalid); + g_test_add_func ("/asn1/seq-of-different", test_seq_of_different); + g_test_add_func ("/asn1/set-order", test_set_order); g_test_add_func ("/asn1/append", test_append); g_test_add_func ("/asn1/append_and_clear", test_append_and_clear); g_test_add_func ("/asn1/setof", test_setof); g_test_add_func ("/asn1/setof_empty", test_setof_empty); g_test_add_func ("/asn1/enumerated", test_enumerated); + g_test_add_func ("/asn1/enumerated-bad", test_enumerated_decode_bad); + g_test_add_func ("/asn1/enumerated-not-in-list", test_enumerated_not_in_list); + g_test_add_func ("/asn1/enumerated-not-set", test_enumerated_not_set); g_test_add_func ("/asn1/nested-fails-with-extra", test_nested_fails_with_extra); g_test_add_func ("/asn1/nested-unexpected", test_nested_unexpected); + g_test_add_func ("/asn1/create-and-decode-invalid", test_create_and_decode_invalid); + g_test_add_func ("/asn1/create-quark", test_create_quark); + g_test_add_func ("/asn1/validate-default", test_validate_default); + g_test_add_func ("/asn1/validate-missing", test_validate_missing); + g_test_add_func ("/asn1/validate-seq-of-child-invalid", test_validate_seq_of_child_invalid); + g_test_add_func ("/asn1/validate-optional-seq", test_validate_optional_seq); + g_test_add_func ("/asn1/get-element/not-set", test_element_get_not_set); g_test_add ("/asn1/node_name", Test, NULL, setup, test_node_name, teardown); g_test_add ("/asn1/asn1_integers", Test, NULL, setup, test_asn1_integers, teardown); g_test_add ("/asn1/boolean_seq", Test, NULL, setup, test_boolean_seq, teardown); g_test_add ("/asn1/write_value", Test, NULL, setup, test_write_value, teardown); g_test_add ("/asn1/element_length_content", Test, NULL, setup, test_element_length_content, teardown); g_test_add ("/asn1/read_element", Test, NULL, setup, test_read_element, teardown); - g_test_add ("/asn1/oid", Test, NULL, setup, test_oid, teardown); g_test_add ("/asn1/general_time", Test, NULL, setup, test_general_time, teardown); g_test_add ("/asn1/utc_time", Test, NULL, setup, test_utc_time, teardown); g_test_add ("/asn1/read_time", Test, NULL, setup, test_read_time, teardown); diff --git a/egg/tests/test-asn1x.c b/egg/tests/test-asn1x.c index ad75e62..78810de 100644 --- a/egg/tests/test-asn1x.c +++ b/egg/tests/test-asn1x.c @@ -78,7 +78,6 @@ 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" }, }; @@ -120,31 +119,22 @@ test_decode_encode (Test *test, const Fixture *fixture = data; GNode *asn; GBytes *encoded; + gboolean ret; asn = egg_asn1x_create (fixture->defs, fixture->identifier); 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 (); - } + ret = egg_asn1x_decode (asn, test->data); + egg_asn1x_assert (ret == TRUE, asn); encoded = egg_asn1x_encode (asn, NULL); - if (encoded == NULL) { - g_warning ("encode of %s failed: %s", fixture->identifier, - egg_asn1x_message (asn)); - g_assert_not_reached (); - } + egg_asn1x_assert (encoded != NULL, asn); /* Decode the encoding */ - if (!egg_asn1x_decode (asn, encoded)) { - g_warning ("decode of encoded %s failed: %s", fixture->identifier, - egg_asn1x_message (asn)); - g_assert_not_reached (); - } + ret = egg_asn1x_decode (asn, encoded); + egg_asn1x_assert (ret == TRUE, asn); egg_asn1x_clear (asn); egg_asn1x_destroy (asn); @@ -152,21 +142,38 @@ test_decode_encode (Test *test, } static void +test_personal_name_invalid (Test *test, + gconstpointer unused) +{ + GNode *asn; + gboolean ret; + + asn = egg_asn1x_create (pkix_asn1_tab, "PersonalName"); + + if (g_test_verbose ()) + egg_asn1x_dump (asn); + + ret = egg_asn1x_decode (asn, test->data); + g_assert (ret == FALSE); + g_assert (strstr (egg_asn1x_message (asn), "content size is out of bounds") != NULL); + + egg_asn1x_destroy (asn); +} + +static void test_pkcs12_decode (Test *test, gconstpointer unused) { GNode *asn; + gboolean ret; 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 (); - } + ret = egg_asn1x_decode (asn, test->data); + egg_asn1x_assert (ret == TRUE, asn); egg_asn1x_destroy (asn); } @@ -179,11 +186,6 @@ main (int argc, char **argv) g_test_init (&argc, &argv, NULL); -#if 0 - /* Build up a personal name, which is a set */ - build_personal_name (); -#endif - 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); @@ -192,8 +194,8 @@ main (int argc, char **argv) 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); + g_test_add ("/asn1x/pkcs5-personal-name/invalid", Test, SRCDIR "/files/test-personalname-invalid.der", + setup, test_personal_name_invalid, teardown); return g_test_run (); } diff --git a/egg/tests/test-symkey.c b/egg/tests/test-symkey.c index e83c394..133cbf9 100644 --- a/egg/tests/test-symkey.c +++ b/egg/tests/test-symkey.c @@ -300,8 +300,6 @@ static const ReadCipher cipher_tests[] = { "\x04\x08\x73\x61\x6c\x74\x73\x61\x6c\x74", 8, "plaintex", "\xB7\x7B\x54\xBF\x29\x4D\x31\x7D" } - - }; typedef struct { @@ -636,7 +634,7 @@ main (int argc, char **argv) egg_libgcrypt_initialize (); /* Suppress these messages in tests */ - g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, null_log_handler, NULL); g_test_add_func ("/symkey/generate_key_simple", test_generate_key_simple); diff --git a/egg/tests/test.asn b/egg/tests/test.asn index 27dbf4a..05676d7 100644 --- a/egg/tests/test.asn +++ b/egg/tests/test.asn @@ -24,12 +24,20 @@ TestUniversal ::= [UNIVERSAL 5] IMPLICIT OCTET STRING TestBitString ::= BIT STRING +test-integers-id OBJECT IDENTIFIER ::= {1 5 13} + TestIntegers ::= SEQUENCE { uint1 INTEGER, uint2 INTEGER, - uint3 INTEGER + uint3 INTEGER DEFAULT 8888 +} + +TestConstant ::= SEQUENCE { + version TestVersion DEFAULT v3 } +TestVersion ::= INTEGER { v1(1), v2(2), v3(3) } + TestData ::= SEQUENCE { data OCTET STRING } @@ -39,10 +47,18 @@ TestBooleanSeq ::= SEQUENCE { boolean2 BOOLEAN } +TestBooleanDefault ::= SEQUENCE { + boolean BOOLEAN DEFAULT TRUE +} + TestOid ::= SEQUENCE { oid OBJECT IDENTIFIER } +TestOidOptional ::= SEQUENCE { + oid OBJECT IDENTIFIER OPTIONAL +} + TestAnySeq ::= SEQUENCE { contents ANY } @@ -56,10 +72,26 @@ TestAnyChoice ::= CHOICE { choiceLongTag [31] ANY } +TestSet ::= SET { + one [1] INTEGER, + two [2] INTEGER, + three [3] INTEGER +} + +TestTagLong ::= [1234] EXPLICIT INTEGER + TestSeqOf ::= SEQUENCE OF INTEGER TestSetOf ::= SET OF INTEGER +TestSeqOfSeq ::= SEQUENCE OF TestIntegers + +TestSeqOfAny ::= SEQUENCE OF ANY + +TestSeqOptional ::= SEQUENCE { + integers TestIntegers OPTIONAL +} + TestEnumerated ::= ENUMERATED { valueZero (0), valueOne (1), -- 2.7.4