diff options
author | Stef Walter <stefw@gnome.org> | 2013-03-14 11:14:52 +0100 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2013-03-15 17:51:04 +0100 |
commit | 5208fc8539aabc626c1699f181e1191d6bb1c787 (patch) | |
tree | dc740b45a209198959a5b14e45db22ee60bbaf4e /common | |
parent | 07a53cecc3220b3811f9db7514e49235fff32b94 (diff) |
asn1: Implement a parsed ASN.1 tree cache
In order to unmarry the parser from the future builder, but still retain
efficiency, we need to be able to cache parsed ASN.1 trees. The ASN.1
cache provides this. In addition it carries around the loaded ASN.1
definitions.
https://bugs.freedesktop.org/show_bug.cgi?id=62329
Diffstat (limited to 'common')
-rw-r--r-- | common/asn1.c | 110 | ||||
-rw-r--r-- | common/asn1.h | 21 | ||||
-rw-r--r-- | common/tests/test-asn1.c | 46 |
3 files changed, 177 insertions, 0 deletions
diff --git a/common/asn1.c b/common/asn1.c index 4f650ee..44f96eb 100644 --- a/common/asn1.c +++ b/common/asn1.c @@ -546,3 +546,113 @@ p11_asn1_tlv_length (const unsigned char *data, return -1; } + +typedef struct { + node_asn *node; + char *struct_name; + size_t length; +} asn1_item; + +static void +free_asn1_item (void *data) +{ + asn1_item *item = data; + free (item->struct_name); + asn1_delete_structure (&item->node); + free (item); +} + +struct _p11_asn1_cache { + p11_dict *defs; + p11_dict *items; +}; + +p11_asn1_cache * +p11_asn1_cache_new (void) +{ + p11_asn1_cache *cache; + + cache = calloc (1, sizeof (p11_asn1_cache)); + return_val_if_fail (cache != NULL, NULL); + + cache->defs = p11_asn1_defs_load (); + return_val_if_fail (cache->defs != NULL, NULL); + + cache->items = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, + NULL, free_asn1_item); + return_val_if_fail (cache->items != NULL, NULL); + + return cache; +} + +node_asn * +p11_asn1_cache_get (p11_asn1_cache *cache, + const char *struct_name, + const unsigned char *der, + size_t der_len) +{ + asn1_item *item; + + return_val_if_fail (cache != NULL, NULL); + return_val_if_fail (struct_name != NULL, NULL); + return_val_if_fail (der != NULL, NULL); + + item = p11_dict_get (cache->items, der); + if (item != NULL) { + return_val_if_fail (item->length == der_len, NULL); + return_val_if_fail (strcmp (item->struct_name, struct_name) == 0, NULL); + return item->node; + } + + return NULL; +} + +void +p11_asn1_cache_take (p11_asn1_cache *cache, + node_asn *node, + const char *struct_name, + const unsigned char *der, + size_t der_len) +{ + asn1_item *item; + + return_if_fail (cache != NULL); + return_if_fail (struct_name != NULL); + return_if_fail (der != NULL); + return_if_fail (der_len != 0); + + item = calloc (1, sizeof (asn1_item)); + return_if_fail (item != NULL); + + item->length = der_len; + item->node = node; + item->struct_name = strdup (struct_name); + return_if_fail (item->struct_name != NULL); + + if (!p11_dict_set (cache->items, (void *)der, item)) + return_if_reached (); +} + +void +p11_asn1_cache_flush (p11_asn1_cache *cache) +{ + return_if_fail (cache != NULL); + p11_dict_clear (cache->items); +} + +p11_dict * +p11_asn1_cache_defs (p11_asn1_cache *cache) +{ + return_val_if_fail (cache != NULL, NULL); + return cache->defs; +} + +void +p11_asn1_cache_free (p11_asn1_cache *cache) +{ + if (!cache) + return; + p11_dict_free (cache->items); + p11_dict_free (cache->defs); + free (cache); +} diff --git a/common/asn1.h b/common/asn1.h index 76a84ed..c79e8f6 100644 --- a/common/asn1.h +++ b/common/asn1.h @@ -39,6 +39,8 @@ #ifndef P11_ASN1_H_ #define P11_ASN1_H_ +typedef struct _p11_asn1_cache p11_asn1_cache; + p11_dict * p11_asn1_defs_load (void); node_asn * p11_asn1_decode (p11_dict *asn1_defs, @@ -62,4 +64,23 @@ time_t p11_asn1_parse_general (const char *time_str, ssize_t p11_asn1_tlv_length (const unsigned char *data, size_t length); +p11_asn1_cache * p11_asn1_cache_new (void); + +p11_dict * p11_asn1_cache_defs (p11_asn1_cache *cache); + +node_asn * p11_asn1_cache_get (p11_asn1_cache *cache, + const char *struct_name, + const unsigned char *der, + size_t der_len); + +void p11_asn1_cache_take (p11_asn1_cache *cache, + node_asn *node, + const char *struct_name, + const unsigned char *der, + size_t der_len); + +void p11_asn1_cache_flush (p11_asn1_cache *cache); + +void p11_asn1_cache_free (p11_asn1_cache *cache); + #endif /* P11_ASN1_H_ */ diff --git a/common/tests/test-asn1.c b/common/tests/test-asn1.c index 0034623..0335fa6 100644 --- a/common/tests/test-asn1.c +++ b/common/tests/test-asn1.c @@ -89,6 +89,51 @@ test_tlv_length (CuTest *cu) teardown (cu); } +static const unsigned char test_eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, +}; + +static void +test_asn1_cache (CuTest *cu) +{ + p11_asn1_cache *cache; + p11_dict *defs; + node_asn *asn; + node_asn *check; + + cache = p11_asn1_cache_new (); + CuAssertPtrNotNull (cu, cache); + + defs = p11_asn1_cache_defs (cache); + CuAssertPtrNotNull (cu, defs); + + asn = p11_asn1_decode (defs, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client), NULL); + CuAssertPtrNotNull (cu, defs); + + /* Place the parsed data in the cache */ + p11_asn1_cache_take (cache, asn, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + + /* Get it back out */ + check = p11_asn1_cache_get (cache, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + CuAssertPtrEquals (cu, asn, check); + + /* Flush should remove it */ + p11_asn1_cache_flush (cache); + check = p11_asn1_cache_get (cache, "PKIX1.ExtKeyUsageSyntax", + test_eku_server_and_client, + sizeof (test_eku_server_and_client)); + CuAssertPtrEquals (cu, NULL, check); + + p11_asn1_cache_free (cache); +} + int main (void) { @@ -100,6 +145,7 @@ main (void) p11_debug_init (); SUITE_ADD_TEST (suite, test_tlv_length); + SUITE_ADD_TEST (suite, test_asn1_cache); CuSuiteRun (suite); CuSuiteSummary (suite, output); |