diff options
Diffstat (limited to 'trust')
-rw-r--r-- | trust/builder.c | 3 | ||||
-rw-r--r-- | trust/extract-info.c | 86 | ||||
-rw-r--r-- | trust/index.c | 18 | ||||
-rw-r--r-- | trust/index.h | 6 | ||||
-rw-r--r-- | trust/module.c | 5 | ||||
-rw-r--r-- | trust/parser.c | 124 | ||||
-rw-r--r-- | trust/parser.h | 7 | ||||
-rw-r--r-- | trust/tests/test-extract.c | 28 | ||||
-rw-r--r-- | trust/tests/test-parser.c | 184 | ||||
-rw-r--r-- | trust/tests/test-token.c | 255 | ||||
-rw-r--r-- | trust/tests/test-trust.c | 75 | ||||
-rw-r--r-- | trust/tests/test-trust.h | 28 | ||||
-rw-r--r-- | trust/token.c | 331 | ||||
-rw-r--r-- | trust/token.h | 3 |
14 files changed, 746 insertions, 407 deletions
diff --git a/trust/builder.c b/trust/builder.c index bfbc42d..f325be6 100644 --- a/trust/builder.c +++ b/trust/builder.c @@ -322,7 +322,8 @@ type_der_cert (p11_builder *builder, { CKA_MODIFIABLE, CREATE | WANT, type_bool }, \ { CKA_PRIVATE, CREATE, type_bool }, \ { CKA_LABEL, CREATE | MODIFY | WANT, type_utf8 }, \ - { CKA_X_GENERATED, CREATE } + { CKA_X_GENERATED, CREATE }, \ + { CKA_X_ORIGIN, NONE } \ static CK_ATTRIBUTE * common_populate (p11_builder *builder, diff --git a/trust/extract-info.c b/trust/extract-info.c index a645d31..ec25bc1 100644 --- a/trust/extract-info.c +++ b/trust/extract-info.c @@ -143,46 +143,66 @@ extract_purposes (p11_extract_info *ex) } static bool -should_collapse_certificate (p11_extract_info *ex, - CK_ATTRIBUTE *value) +check_blacklisted (P11KitIter *iter, + CK_ATTRIBUTE *cert) { - CK_ATTRIBUTE *attrs; + CK_OBJECT_HANDLE dummy; + CK_FUNCTION_LIST *module; + CK_SESSION_HANDLE session; + CK_BBOOL distrusted = CK_TRUE; + CK_ULONG have; + CK_RV rv; - if (!(ex->flags & P11_EXTRACT_COLLAPSE)) - return false; + CK_ATTRIBUTE match[] = { + { CKA_VALUE, cert->pValue, cert->ulValueLen }, + { CKA_X_DISTRUSTED, &distrusted, sizeof (distrusted) }, + }; + + module = p11_kit_iter_get_module (iter); + session = p11_kit_iter_get_session (iter); - if (!ex->already_seen) { - ex->already_seen = p11_dict_new (p11_attr_hash, p11_attr_equal, - NULL, p11_attrs_free); - return_val_if_fail (ex->already_seen != NULL, true); + rv = (module->C_FindObjectsInit) (session, match, 2); + if (rv == CKR_OK) { + rv = (module->C_FindObjects) (session, &dummy, 1, &have); + (module->C_FindObjectsFinal) (session); } - if (p11_dict_get (ex->already_seen, value)) + if (rv != CKR_OK) { + p11_message ("couldn't check if certificate is on blacklist"); return true; + } - attrs = p11_attrs_build (NULL, value, NULL); - return_val_if_fail (attrs != NULL, true); - - if (!p11_dict_set (ex->already_seen, attrs, attrs)) - return_val_if_reached (true); - - return false; + if (have == 0) { + p11_debug ("anchor is not on blacklist"); + return false; + } else { + p11_debug ("anchor is on blacklist"); + return true; + } } static bool -check_trust_flags_match (p11_extract_info *ex) +check_trust_flags (P11KitIter *iter, + p11_extract_info *ex, + CK_ATTRIBUTE *cert) { - CK_BBOOL boolv; + CK_BBOOL trusted; + CK_BBOOL distrusted; int flags = 0; /* If no extract trust flags, then just continue */ if (!(ex->flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST))) return true; - if (p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &boolv) && boolv) + if (p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &trusted) && + trusted && !check_blacklisted (iter, cert)) { flags |= P11_EXTRACT_ANCHORS; - if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &boolv) && boolv) + } + + if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &distrusted) && + distrusted) { flags |= P11_EXTRACT_BLACKLIST; + } /* Any of the flags can match */ if (flags & ex->flags) @@ -218,20 +238,28 @@ extract_certificate (P11KitIter *iter, * If collapsing and have already seen this certificate, and shouldn't * process it even again during this extract procedure. */ - if (should_collapse_certificate (ex, attr)) { - p11_debug ("skipping certificate that has already been seen"); - return false; + if (ex->flags & P11_EXTRACT_COLLAPSE) { + if (!ex->already_seen) { + ex->already_seen = p11_dict_new (p11_attr_hash, p11_attr_equal, + p11_attrs_free, NULL); + return_val_if_fail (ex->already_seen != NULL, true); + } + + if (p11_dict_get (ex->already_seen, attr)) + return false; } - /* - * We do these checks after collapsing, so that blacklisted certificates - * mask out anchors even if we're not exporting blacklisted stuff. - */ - if (!check_trust_flags_match (ex)) { + if (!check_trust_flags (iter, ex, attr)) { p11_debug ("skipping certificate that doesn't match trust flags"); return false; } + if (ex->already_seen) { + if (!p11_dict_set (ex->already_seen, + p11_attrs_build (NULL, attr, NULL), "x")) + return_val_if_reached (true); + } + ex->cert_der = attr->pValue; ex->cert_len = attr->ulValueLen; ex->cert_asn = p11_asn1_decode (ex->asn1_defs, "PKIX1.Certificate", diff --git a/trust/index.c b/trust/index.c index c8632cc..4de65c9 100644 --- a/trust/index.c +++ b/trust/index.c @@ -154,6 +154,7 @@ is_indexable (p11_index *index, case CKA_VALUE: case CKA_OBJECT_ID: case CKA_ID: + case CKA_X_ORIGIN: return true; } @@ -566,13 +567,18 @@ p11_index_replace_all (p11_index *index, handles = p11_index_find_all (index, match, -1); rv = index_replacev (index, handles, key, - (CK_ATTRIBUTE **)replace->elem, - replace->num); + replace ? (CK_ATTRIBUTE **)replace->elem : NULL, + replace ? replace->num : 0); - for (i = 0; i < replace->num; i++) { - if (!replace->elem[i]) { - p11_array_remove (replace, i); - i--; + if (rv == CKR_OK) { + if (replace) + p11_array_clear (replace); + } else { + for (i = 0; replace && i < replace->num; i++) { + if (!replace->elem[i]) { + p11_array_remove (replace, i); + i--; + } } } diff --git a/trust/index.h b/trust/index.h index a221178..2f44d0c 100644 --- a/trust/index.h +++ b/trust/index.h @@ -38,6 +38,7 @@ #include "array.h" #include "compat.h" #include "pkcs11.h" +#include "pkcs11x.h" /* * A boolean value which denotes whether we auto generated @@ -48,6 +49,11 @@ */ #define CKA_X_GENERATED (CKA_X_VENDOR + 8000) +/* + * A string pointing to the filename from which this was loaded. + */ +#define CKA_X_ORIGIN (CKA_X_VENDOR + 8001) + typedef struct _p11_index p11_index; typedef CK_RV (* p11_index_build_cb) (void *data, diff --git a/trust/module.c b/trust/module.c index 5f8692b..22e288c 100644 --- a/trust/module.c +++ b/trust/module.c @@ -1110,8 +1110,11 @@ sys_C_SetAttributeValue (CK_SESSION_HANDLE handle, if (rv == CKR_OK) rv = check_index_writable (session, index); - if (rv == CKR_OK) + if (rv == CKR_OK) { + if (index == p11_token_index (session->token)) + p11_token_reload (session->token, attrs); rv = p11_index_set (index, object, template, count); + } } p11_unlock (); diff --git a/trust/parser.c b/trust/parser.c index 21b693b..c5cbe15 100644 --- a/trust/parser.c +++ b/trust/parser.c @@ -64,11 +64,11 @@ #include <unistd.h> struct _p11_parser { - p11_index *index; p11_asn1_cache *asn1_cache; p11_dict *asn1_defs; p11_persist *persist; char *basename; + p11_array *parsed; int flags; }; @@ -131,114 +131,20 @@ populate_trust (p11_parser *parser, return p11_attrs_build (attrs, &trusted, &distrust, NULL); } -static bool -lookup_cert_duplicate (p11_index *index, - CK_ATTRIBUTE *attrs, - CK_OBJECT_HANDLE *handle, - CK_ATTRIBUTE **dupl) -{ - CK_OBJECT_CLASS klass = CKO_CERTIFICATE; - CK_ATTRIBUTE *value; - - CK_ATTRIBUTE match[] = { - { CKA_VALUE, }, - { CKA_CLASS, &klass, sizeof (klass) }, - { CKA_INVALID }, - }; - - /* - * TODO: This will need to be adapted when we support reload on - * the fly, but for now since we only load once, we can assume - * that any certs already present in the index are duplicates. - */ - - value = p11_attrs_find_valid (attrs, CKA_VALUE); - if (value != NULL) { - memcpy (match, value, sizeof (CK_ATTRIBUTE)); - *handle = p11_index_find (index, match, -1); - if (*handle != 0) { - *dupl = p11_index_lookup (index, *handle); - return true; - } - } - - return false; -} - -static char * -pull_cert_label (CK_ATTRIBUTE *attrs) -{ - char *label; - size_t len; - - label = p11_attrs_find_value (attrs, CKA_LABEL, &len); - if (label) - label = strndup (label, len); - - return label; -} - -static int -calc_cert_priority (CK_ATTRIBUTE *attrs) -{ - CK_BBOOL boolv; - - enum { - PRI_UNKNOWN, - PRI_TRUSTED, - PRI_DISTRUST - }; - - if (p11_attrs_find_bool (attrs, CKA_X_DISTRUSTED, &boolv) && boolv) - return PRI_DISTRUST; - else if (p11_attrs_find_bool (attrs, CKA_TRUSTED, &boolv) && boolv) - return PRI_TRUSTED; - - return PRI_UNKNOWN; -} - static void sink_object (p11_parser *parser, CK_ATTRIBUTE *attrs) { - CK_OBJECT_HANDLE handle; CK_OBJECT_CLASS klass; - CK_ATTRIBUTE *dupl; - char *label; - CK_RV rv; - - /* By default not replacing anything */ - handle = 0; if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_CERTIFICATE) { attrs = populate_trust (parser, attrs); return_if_fail (attrs != NULL); - - if (lookup_cert_duplicate (parser->index, attrs, &handle, &dupl)) { - - /* This is not a good place to be for a well configured system */ - label = pull_cert_label (dupl); - p11_message ("duplicate '%s' certificate found in: %s", - label ? label : "?", parser->basename); - free (label); - - /* - * Nevertheless we provide predictable behavior about what - * overrides what. If we have a lower or equal priority - * to what's there, then just go away, otherwise replace. - */ - if (calc_cert_priority (attrs) <= calc_cert_priority (dupl)) { - p11_attrs_free (attrs); - return; - } - } } - /* If handle is zero, this just adds */ - rv = p11_index_replace (parser->index, handle, attrs); - if (rv != CKR_OK) - p11_message ("couldn't load file into objects: %s", parser->basename); + if (!p11_array_push (parser->parsed, attrs)) + return_if_reached (); } static CK_ATTRIBUTE * @@ -636,8 +542,6 @@ on_pem_block (const char *type, p11_parser *parser = user_data; int ret; - p11_index_batch (parser->index); - if (strcmp (type, "CERTIFICATE") == 0) { ret = parse_der_x509_certificate (parser, contents, length); @@ -649,8 +553,6 @@ on_pem_block (const char *type, ret = P11_PARSE_SUCCESS; } - p11_index_finish (parser->index); - if (ret != P11_PARSE_SUCCESS) p11_message ("Couldn't parse PEM block of type %s", type); } @@ -714,18 +616,18 @@ static parser_func all_parsers[] = { }; p11_parser * -p11_parser_new (p11_index *index, - p11_asn1_cache *asn1_cache) +p11_parser_new (p11_asn1_cache *asn1_cache) { p11_parser parser = { 0, }; - return_val_if_fail (index != NULL, NULL); return_val_if_fail (asn1_cache != NULL, NULL); - parser.index = index; parser.asn1_defs = p11_asn1_cache_defs (asn1_cache); parser.asn1_cache = asn1_cache; + parser.parsed = p11_array_new (p11_attrs_free); + return_val_if_fail (parser.parsed != NULL, NULL); + return memdup (&parser, sizeof (parser)); } @@ -734,9 +636,17 @@ p11_parser_free (p11_parser *parser) { return_if_fail (parser != NULL); p11_persist_free (parser->persist); + p11_array_free (parser->parsed); free (parser); } +p11_array * +p11_parser_parsed (p11_parser *parser) +{ + return_val_if_fail (parser != NULL, NULL); + return parser->parsed; +} + int p11_parse_memory (p11_parser *parser, const char *filename, @@ -749,15 +659,15 @@ p11_parse_memory (p11_parser *parser, int i; return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); + return_val_if_fail (filename != NULL, P11_PARSE_FAILURE); + p11_array_clear (parser->parsed); base = p11_path_base (filename); parser->basename = base; parser->flags = flags; for (i = 0; all_parsers[i] != NULL; i++) { - p11_index_batch (parser->index); ret = (all_parsers[i]) (parser, data, length); - p11_index_finish (parser->index); if (ret != P11_PARSE_UNRECOGNIZED) break; diff --git a/trust/parser.h b/trust/parser.h index ca41d26..f956fb9 100644 --- a/trust/parser.h +++ b/trust/parser.h @@ -55,8 +55,7 @@ enum { typedef struct _p11_parser p11_parser; -p11_parser * p11_parser_new (p11_index *index, - p11_asn1_cache *asn1_cache); +p11_parser * p11_parser_new (p11_asn1_cache *asn1_cache); void p11_parser_free (p11_parser *parser); @@ -70,4 +69,6 @@ int p11_parse_file (p11_parser *parser, const char *filename, int flags); -#endif +p11_array * p11_parser_parsed (p11_parser *parser); + +#endif /* P11_PARSER_H_ */ diff --git a/trust/tests/test-extract.c b/trust/tests/test-extract.c index b121b21..ddb4a49 100644 --- a/trust/tests/test-extract.c +++ b/trust/tests/test-extract.c @@ -380,13 +380,18 @@ test_duplicate_extract (void) } static void -test_duplicate_collapse (void) +test_duplicate_distrusted (void) { CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; + CK_ATTRIBUTE attrs[] = { + { CKA_X_DISTRUSTED, NULL, 0 }, + }; + + CK_BBOOL val; CK_RV rv; - mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted); + mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); test.ex.flags = P11_EXTRACT_COLLAPSE; p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL); @@ -396,6 +401,12 @@ test_duplicate_collapse (void) rv = p11_kit_iter_next (test.iter); assert_num_eq (CKR_OK, rv); + rv = p11_kit_iter_load_attributes (test.iter, attrs, 1); + assert_num_eq (CKR_OK, rv); + assert (p11_attrs_findn_bool (attrs, 1, CKA_X_DISTRUSTED, &val)); + assert_num_eq (val, CK_TRUE); + free (attrs[0].pValue); + rv = p11_kit_iter_next (test.iter); assert_num_eq (CKR_CANCEL, rv); } @@ -404,7 +415,6 @@ static void test_trusted_match (void) { CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) }; - CK_BBOOL boolv; CK_RV rv; mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted); @@ -416,13 +426,6 @@ test_trusted_match (void) p11_kit_iter_begin_with (test.iter, &test.module, 0, 0); rv = p11_kit_iter_next (test.iter); - assert_num_eq (CKR_OK, rv); - - if (!p11_attrs_find_bool (test.ex.attrs, CKA_TRUSTED, &boolv)) - boolv = CK_FALSE; - assert_num_eq (CK_TRUE, boolv); - - rv = p11_kit_iter_next (test.iter); assert_num_eq (CKR_CANCEL, rv); } @@ -470,9 +473,6 @@ test_anytrust_match (void) assert_num_eq (CKR_OK, rv); rv = p11_kit_iter_next (test.iter); - assert_num_eq (CKR_OK, rv); - - rv = p11_kit_iter_next (test.iter); assert_num_eq (CKR_CANCEL, rv); } @@ -495,7 +495,7 @@ main (int argc, p11_test (test_limit_to_purpose_match, "/extract/test_limit_to_purpose_match"); p11_test (test_limit_to_purpose_no_match, "/extract/test_limit_to_purpose_no_match"); p11_test (test_duplicate_extract, "/extract/test_duplicate_extract"); - p11_test (test_duplicate_collapse, "/extract/test_duplicate_collapse"); + p11_test (test_duplicate_distrusted, "/extract/test-duplicate-distrusted"); p11_test (test_trusted_match, "/extract/test_trusted_match"); p11_test (test_distrust_match, "/extract/test_distrust_match"); p11_test (test_anytrust_match, "/extract/test_anytrust_match"); diff --git a/trust/tests/test-parser.c b/trust/tests/test-parser.c index 2b60254..3eee984 100644 --- a/trust/tests/test-parser.c +++ b/trust/tests/test-parser.c @@ -51,24 +51,25 @@ struct { p11_parser *parser; + p11_array *parsed; p11_asn1_cache *cache; - p11_index *index; } test; static void setup (void *unused) { - test.index = p11_index_new (NULL, NULL, NULL); test.cache = p11_asn1_cache_new (); - test.parser = p11_parser_new (test.index, test.cache); + test.parser = p11_parser_new (test.cache); assert_ptr_not_null (test.parser); + + test.parsed = p11_parser_parsed (test.parser); + assert_ptr_not_null (test.parsed); } static void teardown (void *unused) { p11_parser_free (test.parser); - p11_index_free (test.index); p11_asn1_cache_free (test.cache); memset (&test, 0, sizeof (test)); } @@ -85,12 +86,19 @@ static CK_ATTRIBUTE certificate_match[] = { }; static CK_ATTRIBUTE * -parsed_attrs (CK_ATTRIBUTE *match) +parsed_attrs (CK_ATTRIBUTE *match, + int length) { - CK_OBJECT_HANDLE handle; - handle = p11_index_find (test.index, certificate_match, -1); - return p11_index_lookup (test.index, handle); + int i; + + if (length < 0) + length = p11_attrs_count (match); + for (i = 0; i < test.parsed->num; i++) { + if (p11_attrs_matchn (test.parsed->elem[i], match, length)) + return test.parsed->elem[i]; + } + return NULL; } static void @@ -114,9 +122,9 @@ test_parse_der_certificate (void) assert_num_eq (P11_PARSE_SUCCESS, ret); /* Should have gotten certificate */ - assert_num_eq (1, p11_index_size (test.index)); + assert_num_eq (1, test.parsed->num); - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected, cert); } @@ -141,9 +149,9 @@ test_parse_pem_certificate (void) assert_num_eq (P11_PARSE_SUCCESS, ret); /* Should have gotten certificate */ - assert_num_eq (1, p11_index_size (test.index)); + assert_num_eq (1, test.parsed->num); - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected, cert); } @@ -168,9 +176,9 @@ test_parse_p11_kit_persist (void) assert_num_eq (P11_PARSE_SUCCESS, ret); /* Should have gotten certificate */ - assert_num_eq (1, p11_index_size (test.index)); + assert_num_eq (1, test.parsed->num); - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected, cert); } @@ -212,7 +220,6 @@ test_parse_openssl_trusted (void) CK_ATTRIBUTE *cert; CK_ATTRIBUTE *object; - CK_OBJECT_HANDLE handle; int ret; int i; @@ -225,18 +232,15 @@ test_parse_openssl_trusted (void) * - 1 certificate * - 2 stapled extensions */ - assert_num_eq (3, p11_index_size (test.index)); + assert_num_eq (3, test.parsed->num); /* The certificate */ - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected[0], cert); /* The other objects */ for (i = 1; expected[i]; i++) { - handle = p11_index_find (test.index, expected[i], 2); - assert (handle != 0); - - object = p11_index_lookup (test.index, handle); + object = parsed_attrs (expected[i], 2); assert_ptr_not_null (object); test_check_attrs (expected[i], object); @@ -281,7 +285,6 @@ test_parse_openssl_distrusted (void) CK_ATTRIBUTE *cert; CK_ATTRIBUTE *object; - CK_OBJECT_HANDLE handle; int ret; int i; @@ -298,16 +301,13 @@ test_parse_openssl_distrusted (void) * - 1 certificate * - 2 stapled extensions */ - assert_num_eq (3, p11_index_size (test.index)); - cert = parsed_attrs (certificate_match); + assert_num_eq (3, test.parsed->num); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected[0], cert); /* The other objects */ for (i = 1; expected[i]; i++) { - handle = p11_index_find (test.index, expected[i], 2); - assert (handle != 0); - - object = p11_index_lookup (test.index, handle); + object = parsed_attrs (expected[i], 2); assert_ptr_not_null (object); test_check_attrs (expected[i], object); @@ -339,9 +339,9 @@ test_parse_anchor (void) * Should have gotten: * - 1 certificate */ - assert_num_eq (1, p11_index_size (test.index)); + assert_num_eq (1, test.parsed->num); - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (cacert3, cert); } @@ -365,9 +365,9 @@ test_parse_thawte (void) assert_num_eq (P11_PARSE_SUCCESS, ret); /* Should have gotten certificate */ - assert_num_eq (1, p11_index_size (test.index)); + assert_num_eq (1, test.parsed->num); - cert = parsed_attrs (certificate_match); + cert = parsed_attrs (certificate_match, -1); test_check_attrs (expected, cert); } @@ -401,124 +401,6 @@ test_parse_unrecognized (void) p11_message_loud (); } -static void -test_duplicate (void) -{ - CK_ATTRIBUTE cacert3[] = { - { CKA_CLASS, &certificate, sizeof (certificate) }, - { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, - { CKA_TRUSTED, &falsev, sizeof (falsev) }, - { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, - { CKA_INVALID }, - }; - - CK_OBJECT_HANDLE *handles; - CK_ATTRIBUTE *cert; - int ret; - - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0); - assert_num_eq (P11_PARSE_SUCCESS, ret); - - p11_message_quiet (); - - /* This shouldn't be added, should print a message */ - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0); - assert_num_eq (P11_PARSE_SUCCESS, ret); - - assert (strstr (p11_message_last (), "duplicate") != NULL); - - p11_message_loud (); - - /* Should only be one certificate since the above two are identical */ - handles = p11_index_find_all (test.index, cacert3, 2); - assert_ptr_not_null (handles); - assert (handles[0] != 0); - assert (handles[1] == 0); - - cert = p11_index_lookup (test.index, handles[0]); - test_check_attrs (cacert3, cert); - - free (handles); -} - -static void -test_duplicate_priority (void) -{ - CK_ATTRIBUTE cacert3[] = { - { CKA_CLASS, &certificate, sizeof (certificate) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE trusted[] = { - { CKA_CLASS, &certificate, sizeof (certificate) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_TRUSTED, &truev, sizeof (truev) }, - { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE distrust[] = { - { CKA_CLASS, &certificate, sizeof (certificate) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_TRUSTED, &falsev, sizeof (falsev) }, - { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, - { CKA_INVALID }, - }; - - CK_OBJECT_HANDLE *handles; - CK_ATTRIBUTE *cert; - int ret; - - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0); - assert_num_eq (P11_PARSE_SUCCESS, ret); - - p11_message_quiet (); - - /* This shouldn't be added, should print a message */ - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", - P11_PARSE_FLAG_ANCHOR); - assert_num_eq (P11_PARSE_SUCCESS, ret); - - assert (strstr (p11_message_last (), "duplicate") != NULL); - - p11_message_loud (); - - /* We should now find the trusted certificate */ - handles = p11_index_find_all (test.index, cacert3, 2); - assert_ptr_not_null (handles); - assert (handles[0] != 0); - assert (handles[1] == 0); - cert = p11_index_lookup (test.index, handles[0]); - test_check_attrs (trusted, cert); - free (handles); - - /* Now add a distrutsed one, this should override the trusted */ - - p11_message_quiet (); - - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", - P11_PARSE_FLAG_BLACKLIST); - assert_num_eq (P11_PARSE_SUCCESS, ret); - - p11_message_loud (); - - /* We should now find the distrusted certificate */ - handles = p11_index_find_all (test.index, cacert3, 2); - assert_ptr_not_null (handles); - assert (handles[0] != 0); - assert (handles[1] == 0); - cert = p11_index_lookup (test.index, handles[0]); - test_check_attrs (distrust, cert); - free (handles); -} - int main (int argc, char *argv[]) @@ -533,7 +415,5 @@ main (int argc, p11_test (test_parse_thawte, "/parser/parse_thawte"); p11_test (test_parse_invalid_file, "/parser/parse_invalid_file"); p11_test (test_parse_unrecognized, "/parser/parse_unrecognized"); - p11_test (test_duplicate, "/parser/duplicate"); - p11_test (test_duplicate_priority, "/parser/duplicate_priority"); return p11_test_run (argc, argv); } diff --git a/trust/tests/test-token.c b/trust/tests/test-token.c index d372814..a518c9e 100644 --- a/trust/tests/test-token.c +++ b/trust/tests/test-token.c @@ -47,8 +47,14 @@ #include "message.h" #include "token.h" +static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; +static CK_BBOOL falsev = CK_FALSE; +static CK_BBOOL truev = CK_TRUE; + struct { p11_token *token; + p11_index *index; + char *directory; } test; static void @@ -56,6 +62,19 @@ setup (void *path) { test.token = p11_token_new (333, path, "Label"); assert_ptr_not_null (test.token); + + test.index = p11_token_index (test.token); + assert_ptr_not_null (test.token); +} + +static void +setup_temp (void *unused) +{ + test.directory = p11_path_expand ("$TEMP/test-module.XXXXXX"); + if (!mkdtemp (test.directory)) + assert_not_reached (); + + setup (test.directory); } static void @@ -66,15 +85,23 @@ teardown (void *path) } static void +teardown_temp (void *unused) +{ + test_delete_directory (test.directory); + free (test.directory); + teardown (test.directory); +} + +static void test_token_load (void *path) { p11_index *index; int count; count = p11_token_load (test.token); - assert_num_eq (7, count); + assert_num_eq (6, count); - /* A certificate and trust object for each parsed object + builtin */ + /* A certificate and trust object for each parsed object */ index = p11_token_index (test.token); assert (((count - 1) * 2) + 1 <= p11_index_size (index)); } @@ -82,10 +109,6 @@ test_token_load (void *path) static void test_token_flags (void *path) { - CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; - CK_BBOOL falsev = CK_FALSE; - CK_BBOOL truev = CK_TRUE; - /* * blacklist comes from the input/distrust.pem file. It is not in the blacklist * directory, but is an OpenSSL trusted certificate file, and is marked @@ -228,24 +251,8 @@ test_not_writable (void) static void test_writable_exists (void) { - char *directory; - p11_token *token; - - directory = p11_path_expand ("$TEMP/test-module.XXXXXX"); - if (!mkdtemp (directory)) - assert_not_reached (); - - token = p11_token_new (333, directory, "Label"); - /* A writable directory since we created it */ - assert (p11_token_is_writable (token)); - - p11_token_free (token); - - if (rmdir (directory) < 0) - assert_not_reached (); - - free (directory); + assert (p11_token_is_writable (test.token)); } static void @@ -276,6 +283,196 @@ test_writable_no_exist (void) free (directory); } +static void +test_load_already (void) +{ + CK_ATTRIBUTE cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + CK_OBJECT_HANDLE handle; + int ret; + + test_write_file (test.directory, "test.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 1); + handle = p11_index_find (test.index, cert, -1); + assert (handle != 0); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 0); + assert_num_eq (p11_index_find (test.index, cert, -1), handle); +} + +static void +test_load_unreadable (void) +{ + CK_ATTRIBUTE cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + int ret; + + test_write_file (test.directory, "test.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 1); + assert (p11_index_find (test.index, cert, -1) != 0); + + test_write_file (test.directory, "test.cer", "", 0); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 0); + assert (p11_index_find (test.index, cert, -1) == 0); +} + +static void +test_load_gone (void) +{ + CK_ATTRIBUTE cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + int ret; + + test_write_file (test.directory, "test.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 1); + assert (p11_index_find (test.index, cert, -1) != 0); + + test_delete_file (test.directory, "test.cer"); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 0); + assert (p11_index_find (test.index, cert, -1) == 0); +} + +static void +test_load_found (void) +{ + CK_ATTRIBUTE cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + int ret; + + ret = p11_token_load (test.token); + assert_num_eq (ret, 0); + assert (p11_index_find (test.index, cert, -1) == 0); + + test_write_file (test.directory, "test.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 1); + assert (p11_index_find (test.index, cert, -1) != 0); +} + +static void +test_reload_changed (void) +{ + CK_ATTRIBUTE cacert3[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE verisign[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_OBJECT_HANDLE handle; + int ret; + + /* Just one file */ + test_write_file (test.directory, "test.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 1); + handle = p11_index_find (test.index, cacert3, -1); + assert (handle != 0); + + /* Replace the file with verisign */ + test_write_file (test.directory, "test.cer", verisign_v1_ca, + sizeof (verisign_v1_ca)); + + /* Add another file with cacert3, but not reloaded */ + test_write_file (test.directory, "another.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + + attrs = p11_index_lookup (test.index, handle); + assert_ptr_not_null (attrs); + p11_token_reload (test.token, attrs); + + assert (p11_index_find (test.index, cacert3, -1) == 0); + assert (p11_index_find (test.index, verisign, -1) != 0); +} + +static void +test_reload_gone (void) +{ + CK_ATTRIBUTE cacert3[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE verisign[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_OBJECT_HANDLE handle; + int ret; + + /* Just one file */ + test_write_file (test.directory, "cacert3.cer", test_cacert3_ca_der, + sizeof (test_cacert3_ca_der)); + test_write_file (test.directory, "verisign.cer", verisign_v1_ca, + sizeof (verisign_v1_ca)); + + ret = p11_token_load (test.token); + assert_num_eq (ret, 2); + handle = p11_index_find (test.index, cacert3, -1); + assert (handle != 0); + assert (p11_index_find (test.index, verisign, -1) != 0); + + test_delete_file (test.directory, "cacert3.cer"); + test_delete_file (test.directory, "verisign.cer"); + + attrs = p11_index_lookup (test.index, handle); + assert_ptr_not_null (attrs); + p11_token_reload (test.token, attrs); + + assert (p11_index_find (test.index, cacert3, -1) == 0); + assert (p11_index_find (test.index, verisign, -1) != 0); +} + int main (int argc, char *argv[]) @@ -283,16 +480,22 @@ main (int argc, p11_fixture (setup, teardown); p11_testx (test_token_load, SRCDIR "/input", "/token/load"); p11_testx (test_token_flags, SRCDIR "/input", "/token/flags"); - - p11_fixture (setup, teardown); p11_testx (test_token_path, "/wheee", "/token/path"); p11_testx (test_token_label, "/wheee", "/token/label"); p11_testx (test_token_slot, "/unneeded", "/token/slot"); p11_fixture (NULL, NULL); p11_test (test_not_writable, "/token/not-writable"); - p11_test (test_writable_exists, "/token/writable-exists"); p11_test (test_writable_no_exist, "/token/writable-no-exist"); + p11_fixture (setup_temp, teardown_temp); + p11_test (test_writable_exists, "/token/writable-exists"); + p11_test (test_load_found, "/token/load-found"); + p11_test (test_load_already, "/token/load-already"); + p11_test (test_load_unreadable, "/token/load-unreadable"); + p11_test (test_load_gone, "/token/load-gone"); + p11_test (test_reload_changed, "/token/reload-changed"); + p11_test (test_reload_gone, "/token/reload-gone"); + return p11_test_run (argc, argv); } diff --git a/trust/tests/test-trust.c b/trust/tests/test-trust.c index 33ba19e..fceaea7 100644 --- a/trust/tests/test-trust.c +++ b/trust/tests/test-trust.c @@ -324,3 +324,78 @@ test_check_directory_msg (const char *file, p11_dict_free (files); } + +void +test_write_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const void *contents, + size_t length) +{ + char *path; + FILE *f; + + if (asprintf (&path, "%s/%s", directory, name) < 0) + assert_not_reached (); + + f = fopen (path, "wb"); + if (f == NULL) { + p11_test_fail (file, line, function, "Couldn't open file for writing: %s: %s", + path, strerror (errno)); + } + + if (fwrite (contents, 1, length, f) != length || + fclose (f) != 0) { + p11_test_fail (file, line, function, "Couldn't write file: %s: %s", + path, strerror (errno)); + } + + free (path); +} + +void +test_delete_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name) +{ + char *path; + + if (asprintf (&path, "%s/%s", directory, name) < 0) + assert_not_reached (); + + if (unlink (path) < 0) + p11_test_fail (file, line, function, "Couldn't delete file: %s", path); + + free (path); +} + +void +test_delete_directory_msg (const char *file, + int line, + const char *function, + const char *directory) +{ + struct dirent *dp; + DIR *dir; + + dir = opendir (directory); + if (dir == NULL) + p11_test_fail (file ,line, function, "Couldn't open directory: %s", directory); + + while ((dp = readdir (dir)) != NULL) { + if (strcmp (dp->d_name, ".") == 0 || + strcmp (dp->d_name, "..") == 0) + continue; + + test_delete_file_msg (file, line, function, directory, dp->d_name); + } + + closedir (dir); + + if (rmdir (directory) < 0) + p11_test_fail (file, line, function, "Couldn't remove directory: %s", directory); +} diff --git a/trust/tests/test-trust.h b/trust/tests/test-trust.h index 18ca13c..4d2c5bf 100644 --- a/trust/tests/test-trust.h +++ b/trust/tests/test-trust.h @@ -344,4 +344,32 @@ void test_check_directory_msg (const char *file, (test_check_directory_msg (__FILE__, __LINE__, __FUNCTION__, directory, \ test_check_directory_files files)) +#define test_write_file(directory, name, data, length) \ + (test_write_file_msg (__FILE__, __LINE__, __FUNCTION__, directory, name, data, length)) + +void test_write_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name, + const void *contents, + size_t length); + +#define test_delete_file(directory, name) \ + (test_delete_file_msg (__FILE__, __LINE__, __FUNCTION__, directory, name)) + +void test_delete_file_msg (const char *file, + int line, + const char *function, + const char *directory, + const char *name); + +#define test_delete_directory(directory) \ + (test_delete_directory_msg (__FILE__, __LINE__, __FUNCTION__, directory)) + +void test_delete_directory_msg (const char *file, + int line, + const char *function, + const char *directory); + #endif /* TEST_DATA_H_ */ diff --git a/trust/token.c b/trust/token.c index c5991df..ec34f6c 100644 --- a/trust/token.c +++ b/trust/token.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Red Hat Inc. + * Copyright (C) 2012-2013 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,48 +58,200 @@ #include <string.h> struct _p11_token { - p11_parser *parser; - p11_index *index; - p11_builder *builder; - char *path; - char *label; - CK_SLOT_ID slot; - int loaded; + p11_parser *parser; /* Parser we use to load files */ + p11_index *index; /* Index we load objects into */ + p11_builder *builder; /* Expands objects and applies policy */ + p11_dict *loaded; /* stat structs for loaded files, track reloads */ + + char *path; /* Main path to load from */ + char *anchors; /* Path to load anchors from */ + char *blacklist; /* Path to load blacklist from */ + char *label; /* The token label */ + CK_SLOT_ID slot; /* The slot id */ bool checked_writable; bool is_writable; }; +static bool +loader_is_necessary (p11_token *token, + const char *filename, + struct stat *sb) +{ + struct stat *last; + + last = p11_dict_get (token->loaded, filename); + + /* Never seen this before, load it */ + if (last == NULL) + return true; + + /* + * If any of these are different assume that the file + * needs to be reloaded + */ + return (sb->st_mode != last->st_mode || + sb->st_mtime != last->st_mtime || + sb->st_size != last->st_size); +} + +static void +loader_was_loaded (p11_token *token, + const char *filename, + struct stat *sb) +{ + char *key; + + key = strdup (filename); + return_if_fail (key != NULL); + + sb = memdup (sb, sizeof (struct stat)); + return_if_fail (sb != NULL); + + /* Track the info about this file, so we don't reload unnecessarily */ + if (!p11_dict_set (token->loaded, key, sb)) + return_if_reached (); +} + +static void +loader_not_loaded (p11_token *token, + const char *filename) +{ + /* No longer track info about this file */ + p11_dict_remove (token->loaded, filename); +} + +static void +loader_gone_file (p11_token *token, + const char *filename) +{ + CK_ATTRIBUTE origin[] = { + { CKA_X_ORIGIN, (void *)filename, strlen (filename) }, + { CKA_INVALID }, + }; + + CK_RV rv; + + /* Remove everything at this origin */ + rv = p11_index_replace_all (token->index, origin, CKA_INVALID, NULL); + return_if_fail (rv == CKR_OK); + + /* No longer track info about this file */ + loader_not_loaded (token, filename); +} + static int loader_load_file (p11_token *token, const char *filename, - struct stat *sb, - int flags) + struct stat *sb) { + CK_ATTRIBUTE origin[] = { + { CKA_X_ORIGIN, (void *)filename, strlen (filename) }, + { CKA_INVALID }, + }; + + CK_BBOOL modifiablev; + + CK_ATTRIBUTE modifiable = { + CKA_MODIFIABLE, + &modifiablev, + sizeof (modifiablev) + }; + + p11_array *parsed; + CK_RV rv; + int flags; int ret; + int i; + + /* Check if this file is already loaded */ + if (!loader_is_necessary (token, filename, sb)) + return 0; + + flags = P11_PARSE_FLAG_NONE; + + /* If it's in the anchors subdirectory, treat as an anchor */ + if (p11_path_prefix (filename, token->anchors)) + flags = P11_PARSE_FLAG_ANCHOR; + + /* If it's in the blacklist subdirectory, treat as a blacklist */ + else if (p11_path_prefix (filename, token->blacklist)) + flags = P11_PARSE_FLAG_BLACKLIST; + + /* If the token is just one path, then assume they are anchors */ + else if (strcmp (filename, token->path) == 0 && !S_ISDIR (sb->st_mode)) + flags = P11_PARSE_FLAG_ANCHOR; ret = p11_parse_file (token->parser, filename, flags); switch (ret) { case P11_PARSE_SUCCESS: p11_debug ("loaded: %s", filename); - return 1; + break; case P11_PARSE_UNRECOGNIZED: p11_debug ("skipped: %s", filename); + loader_gone_file (token, filename); return 0; default: p11_debug ("failed to parse: %s", filename); + loader_gone_file (token, filename); return 0; } + + /* TODO: We should check if in the right format */ + modifiablev = CK_FALSE; + + /* Update each parsed object with the origin */ + parsed = p11_parser_parsed (token->parser); + for (i = 0; i < parsed->num; i++) { + parsed->elem[i] = p11_attrs_build (parsed->elem[i], origin, &modifiable, NULL); + return_val_if_fail (parsed->elem[i] != NULL, 0); + } + + p11_index_batch (token->index); + + /* Now place all of these in the index */ + rv = p11_index_replace_all (token->index, origin, CKA_CLASS, parsed); + + p11_index_finish (token->index); + + if (rv != CKR_OK) { + p11_message ("couldn't load file into objects: %s", filename); + return 0; + } + + loader_was_loaded (token, filename, sb); + return 1; +} + +static int +loader_load_if_file (p11_token *token, + const char *path) +{ + struct stat sb; + + if (stat (path, &sb) < 0) { + if (errno == ENOENT) { + p11_message ("couldn't stat path: %s: %s", + path, strerror (errno)); + } + + } else if (!S_ISDIR (sb.st_mode)) { + return loader_load_file (token, path, &sb); + } + + /* Perhaps the file became unloadable, so track properly */ + loader_gone_file (token, path); + return 0; } static int loader_load_directory (p11_token *token, const char *directory, - int flags) + p11_dict *present) { + p11_dictiter iter; struct dirent *dp; - struct stat sb; char *path; int total = 0; int ret; @@ -110,6 +262,7 @@ loader_load_directory (p11_token *token, if (!dir) { p11_message ("couldn't list directory: %s: %s", directory, strerror (errno)); + loader_not_loaded (token, directory); return 0; } @@ -118,81 +271,81 @@ loader_load_directory (p11_token *token, path = p11_path_build (directory, dp->d_name, NULL); return_val_if_fail (path != NULL, -1); - if (stat (path, &sb) < 0) { - p11_message ("couldn't stat path: %s", path); + ret = loader_load_if_file (token, path); + return_val_if_fail (ret >=0, -1); + total += ret; - } else if (!S_ISDIR (sb.st_mode)) { - ret = loader_load_file (token, path, &sb, flags); - return_val_if_fail (ret >= 0, ret); - total += ret; - } + /* Make note that this file was seen */ + p11_dict_remove (present, path); free (path); } closedir (dir); - return total; -} -static int -loader_load_subdirectory (p11_token *token, - const char *directory, - const char *subdir, - int flags) -{ - struct stat sb; - char *path; - int ret = 0; + /* All other files that were present, not here now */ + p11_dict_iterate (present, &iter); + while (p11_dict_next (&iter, (void **)&path, NULL)) + loader_gone_file (token, path); - if (asprintf (&path, "%s/%s", directory, subdir) < 0) - return_val_if_reached (-1); - - if (stat (path, &sb) >= 0 && S_ISDIR (sb.st_mode)) - ret = loader_load_directory (token, path, flags); - - free (path); - return ret; + return total; } static int loader_load_path (p11_token *token, const char *path) { + p11_dictiter iter; + p11_dict *present; + char *filename; struct stat sb; int total; int ret; if (stat (path, &sb) < 0) { - if (errno == ENOENT) { - p11_message ("trust certificate path does not exist: %s", - path); - } else { + if (errno != ENOENT) { p11_message ("cannot access trust certificate path: %s: %s", path, strerror (errno)); } - + loader_gone_file (token, path); return 0; } if (S_ISDIR (sb.st_mode)) { - total = 0; - ret = loader_load_subdirectory (token, path, "anchors", P11_PARSE_FLAG_ANCHOR); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* All the files we know about at this path */ + present = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); + p11_dict_iterate (token->loaded, &iter); + while (p11_dict_next (&iter, (void **)&filename, NULL)) { + if (p11_path_prefix (filename, path)) { + if (!p11_dict_set (present, filename, filename)) + return_val_if_reached (-1); + } + } - ret = loader_load_subdirectory (token, path, "blacklist", P11_PARSE_FLAG_BLACKLIST); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* If the directory has changed, reload it */ + if (loader_is_necessary (token, path, &sb)) { + ret = loader_load_directory (token, path, present); - ret = loader_load_directory (token, path, P11_PARSE_FLAG_NONE); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* Directory didn't change, but maybe files changed? */ + } else { + total = 0; + p11_dict_iterate (present, &iter); + while (p11_dict_next (&iter, (void **)&filename, NULL)) { + ret = loader_load_if_file (token, filename); + return_val_if_fail (ret >= 0, ret); + total += ret; + } + } + + p11_dict_free (present); + loader_was_loaded (token, path, &sb); - return total; } else { - return loader_load_file (token, path, &sb, P11_PARSE_FLAG_ANCHOR); + ret = loader_load_file (token, path, &sb); } + + return ret; } static int @@ -223,19 +376,49 @@ load_builtin_objects (p11_token *token) int p11_token_load (p11_token *token) { - int builtins; - int count; + int total = 0; + int ret; - if (token->loaded) - return 0; - token->loaded = 1; + ret = loader_load_path (token, token->path); + return_val_if_fail (ret >= 0, -1); + total += ret; + + ret = loader_load_path (token, token->anchors); + return_val_if_fail (ret >= 0, -1); + total += ret; + + ret = loader_load_path (token, token->blacklist); + return_val_if_fail (ret >= 0, -1); + total += ret; + + return total; +} - builtins = load_builtin_objects (token); +void +p11_token_reload (p11_token *token, + CK_ATTRIBUTE *attrs) +{ + CK_ATTRIBUTE *attr; + struct stat sb; + char *origin; - count = loader_load_path (token, token->path); - return_val_if_fail (count >= 0, count); + attr = p11_attrs_find (attrs, CKA_X_ORIGIN); + if (attr == NULL) + return; - return count + builtins; + origin = strndup (attr->pValue, attr->ulValueLen); + return_if_fail (origin != NULL); + + if (stat (origin, &sb) < 0) { + if (errno == ENOENT) { + loader_gone_file (token, origin); + } else { + p11_message ("cannot access trust file: %s: %s", + origin, strerror (errno)); + } + } else { + loader_load_file (token, origin, &sb); + } } void @@ -247,7 +430,10 @@ p11_token_free (p11_token *token) p11_index_free (token->index); p11_parser_free (token->parser); p11_builder_free (token->builder); + p11_dict_free (token->loaded); free (token->path); + free (token->anchors); + free (token->blacklist); free (token->label); free (token); } @@ -273,18 +459,27 @@ p11_token_new (CK_SLOT_ID slot, token->builder); return_val_if_fail (token->index != NULL, NULL); - token->parser = p11_parser_new (token->index, - p11_builder_get_cache (token->builder)); + token->parser = p11_parser_new (p11_builder_get_cache (token->builder)); return_val_if_fail (token->parser != NULL, NULL); + token->loaded = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, free); + return_val_if_fail (token->loaded != NULL, NULL); + token->path = strdup (path); return_val_if_fail (token->path != NULL, NULL); + token->anchors = p11_path_build (token->path, "anchors", NULL); + return_val_if_fail (token->anchors != NULL, NULL); + + token->blacklist = p11_path_build (token->path, "blacklist", NULL); + return_val_if_fail (token->blacklist != NULL, NULL); + token->label = strdup (label); return_val_if_fail (token->label != NULL, NULL); token->slot = slot; - token->loaded = 0; + + load_builtin_objects (token); p11_debug ("token: %s: %s", token->label, token->path); return token; diff --git a/trust/token.h b/trust/token.h index 49140bb..6d50c6c 100644 --- a/trust/token.h +++ b/trust/token.h @@ -49,6 +49,9 @@ void p11_token_free (p11_token *token); int p11_token_load (p11_token *token); +void p11_token_reload (p11_token *token, + CK_ATTRIBUTE *attrs); + p11_index * p11_token_index (p11_token *token); const char * p11_token_get_path (p11_token *token); |