]> granicus.if.org Git - p11-kit/commitdiff
asn1: Implement a parsed ASN.1 tree cache
authorStef Walter <stefw@gnome.org>
Thu, 14 Mar 2013 10:14:52 +0000 (11:14 +0100)
committerStef Walter <stefw@gnome.org>
Fri, 15 Mar 2013 16:51:04 +0000 (17:51 +0100)
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

common/asn1.c
common/asn1.h
common/tests/test-asn1.c

index 4f650ee3164c795926f1deddc17c850a533aff31..44f96ebfa1830aa95d841b5a33048cbdaf15d833 100644 (file)
@@ -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);
+}
index 76a84eda2a84e5d4f9c4eac417de6bf8ef12f42a..c79e8f6993a864f94c72e93a01112d8d7519ba41 100644 (file)
@@ -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_ */
index 00346236fb829cb647418966e9ad528ae415b952..0335fa6334878907427721747d0f0b48e802cb7a 100644 (file)
@@ -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);