summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-03-15 09:22:57 +0100
committerStef Walter <stefw@gnome.org>2013-03-15 17:44:32 +0100
commit07a53cecc3220b3811f9db7514e49235fff32b94 (patch)
tree19b9d244a5750ec7e577bef556332f5f111b585b /tools
parent7fc0ecd1ca7840e71958e62163b27d645c936c25 (diff)
extract: Combine trust policy when extracting
* Collapse multiple identical certificates coming from different tokens. Note that if a certificate should not be placed multiple times on a token. We cannot know which one to respect. * Add a new extract filter: --trust-policy This extracts all anchor and blacklist information https://bugs.freedesktop.org/show_bug.cgi?id=61497
Diffstat (limited to 'tools')
-rw-r--r--tools/extract-info.c80
-rw-r--r--tools/extract.c82
-rw-r--r--tools/extract.h4
-rw-r--r--tools/tests/test-extract.c171
4 files changed, 297 insertions, 40 deletions
diff --git a/tools/extract-info.c b/tools/extract-info.c
index 536d36a..da84bbe 100644
--- a/tools/extract-info.c
+++ b/tools/extract-info.c
@@ -34,6 +34,8 @@
#include "config.h"
+#define P11_DEBUG_FLAG P11_DEBUG_TOOL
+
#include "attrs.h"
#include "debug.h"
#include "oid.h"
@@ -147,6 +149,55 @@ extract_purposes (p11_extract_info *ex)
}
static bool
+should_collapse_certificate (p11_extract_info *ex,
+ CK_ATTRIBUTE *value)
+{
+ CK_ATTRIBUTE *attrs;
+
+ if (!(ex->flags & P11_EXTRACT_COLLAPSE))
+ return false;
+
+ 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);
+ }
+
+ if (p11_dict_get (ex->already_seen, value))
+ 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;
+}
+
+static bool
+check_trust_flags_match (p11_extract_info *ex)
+{
+ CK_BBOOL boolv;
+ 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)
+ flags |= P11_EXTRACT_ANCHORS;
+ if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &boolv) && boolv)
+ flags |= P11_EXTRACT_BLACKLIST;
+
+ /* Any of the flags can match */
+ if (flags & ex->flags)
+ return true;
+
+ return false;
+}
+
+static bool
extract_certificate (P11KitIter *iter,
p11_extract_info *ex)
{
@@ -157,12 +208,34 @@ extract_certificate (P11KitIter *iter,
/* Don't even bother with not X.509 certificates */
if (!p11_attrs_find_ulong (ex->attrs, CKA_CERTIFICATE_TYPE, &type))
type = (CK_ULONG)-1;
- if (type != CKC_X_509)
+ if (type != CKC_X_509) {
+ p11_debug ("skipping non X.509 certificate");
return false;
+ }
attr = p11_attrs_find_valid (ex->attrs, CKA_VALUE);
- if (!attr || !attr->pValue)
+ if (!attr || !attr->pValue) {
+ p11_debug ("skipping certificate without a value");
return false;
+ }
+
+ /*
+ * 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;
+ }
+
+ /*
+ * 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)) {
+ p11_debug ("skipping certificate that doesn't match trust flags");
+ return false;
+ }
ex->cert_der = attr->pValue;
ex->cert_len = attr->ulValueLen;
@@ -308,6 +381,9 @@ p11_extract_info_cleanup (p11_extract_info *ex)
p11_dict_free (ex->limit_to_purposes);
ex->limit_to_purposes = NULL;
+ p11_dict_free (ex->already_seen);
+ ex->already_seen = NULL;
+
p11_dict_free (ex->asn1_defs);
ex->asn1_defs = NULL;
}
diff --git a/tools/extract.c b/tools/extract.c
index 6bdedfe..cf08ae9 100644
--- a/tools/extract.c
+++ b/tools/extract.c
@@ -57,18 +57,16 @@
static bool
filter_argument (const char *optarg,
P11KitUri **uri,
- CK_ATTRIBUTE **match)
+ CK_ATTRIBUTE **match,
+ int *flags)
{
CK_ATTRIBUTE *attrs;
int ret;
- CK_BBOOL vtrue = CK_TRUE;
CK_OBJECT_CLASS vcertificate = CKO_CERTIFICATE;
CK_ULONG vauthority = 2;
CK_CERTIFICATE_TYPE vx509 = CKC_X_509;
- CK_ATTRIBUTE trusted = { CKA_TRUSTED, &vtrue, sizeof (vtrue) };
- CK_ATTRIBUTE distrusted = { CKA_X_DISTRUSTED, &vtrue, sizeof (vtrue) };
CK_ATTRIBUTE certificate = { CKA_CLASS, &vcertificate, sizeof (vcertificate) };
CK_ATTRIBUTE authority = { CKA_CERTIFICATE_CATEGORY, &vauthority, sizeof (vauthority) };
CK_ATTRIBUTE x509 = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) };
@@ -88,13 +86,20 @@ filter_argument (const char *optarg,
}
if (strcmp (optarg, "ca-anchors") == 0) {
- attrs = p11_attrs_build (NULL, &trusted, &certificate, &authority, &x509, NULL);
+ attrs = p11_attrs_build (NULL, &certificate, &authority, &x509, NULL);
+ *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_COLLAPSE;
+
+ } else if (strcmp (optarg, "trust-policy") == 0) {
+ attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
+ *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE;
} else if (strcmp (optarg, "blacklist") == 0) {
- attrs = p11_attrs_build (NULL, &distrusted, &certificate, &x509, NULL);
+ attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
+ *flags |= P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE;
} else if (strcmp (optarg, "certificates") == 0) {
attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
+ *flags |= P11_EXTRACT_COLLAPSE;
} else {
p11_message ("unsupported or unrecognized filter: %s", optarg);
@@ -205,7 +210,7 @@ format_argument (const char *optarg,
static void
limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules,
- CK_ATTRIBUTE *match)
+ int flags)
{
char *string;
int i, out;
@@ -215,8 +220,7 @@ limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules,
* we get from modules explicitly marked as containing trust-policy.
*/
- if (!p11_attrs_find (match, CKA_TRUSTED) &&
- !p11_attrs_find (match, CKA_X_DISTRUSTED))
+ if ((flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST)) == 0)
return;
/* Count the number of modules */
@@ -239,10 +243,10 @@ limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules,
p11_message ("no modules containing trust policy are registered");
}
-static void
-limit_purposes_if_necessary (p11_extract_info *ex,
- p11_extract_func func,
- CK_ATTRIBUTE *match)
+static bool
+validate_filter_and_format (p11_extract_info *ex,
+ p11_extract_func func,
+ CK_ATTRIBUTE *match)
{
int i;
@@ -253,27 +257,41 @@ limit_purposes_if_necessary (p11_extract_info *ex,
* default purpose to limit to.
*/
- static p11_extract_func format_supports_purposes[] = {
+ static p11_extract_func supports_trust_policy[] = {
p11_extract_openssl_bundle,
p11_extract_openssl_directory,
NULL
};
- /* Check if looking for anchors */
- if (!p11_attrs_find (match, CKA_TRUSTED))
- return;
+ for (i = 0; supports_trust_policy[i] != NULL; i++) {
+ if (func == supports_trust_policy[i])
+ return true;
+ }
- /* Already limiting to one or more purposes */
- if (ex->limit_to_purposes)
- return;
+ if ((ex->flags & P11_EXTRACT_ANCHORS) &&
+ (ex->flags & P11_EXTRACT_BLACKLIST)) {
+ /*
+ * If we're extracting *both* anchors and blacklist, then we must have
+ * a format that can represent the different types of information.
+ */
- for (i = 0; format_supports_purposes[i] != NULL; i++) {
- if (func == format_supports_purposes[i])
- return;
+ p11_message ("format does not support trust policy");
+ return false;
+
+ } else if (ex->flags & P11_EXTRACT_ANCHORS) {
+
+ /*
+ * If we're extracting anchors, then we must have either limited the
+ * purposes, or have a format that can represent multiple purposes.
+ */
+
+ if (!ex->limit_to_purposes) {
+ p11_message ("format does not support multiple purposes, defaulting to 'server-auth'");
+ p11_extract_info_limit_purpose (ex, P11_OID_SERVER_AUTH_STR);
+ }
}
- p11_message ("format does not support trust policy, limiting to purpose server-auth");
- p11_extract_info_limit_purpose (ex, P11_OID_SERVER_AUTH_STR);
+ return true;
}
int
@@ -319,6 +337,7 @@ p11_tool_extract (int argc,
"filter of what to export\n"
" ca-anchors certificate anchors (default)\n"
" blacklist blacklisted certificates\n"
+ " trust-policy anchors and blacklist\n"
" certificates all certificates\n"
" pkcs11:object=xx a PKCS#11 URI",
"what",
@@ -368,7 +387,7 @@ p11_tool_extract (int argc,
ex.flags |= P11_EXTRACT_COMMENT;
break;
case opt_filter:
- if (!filter_argument (optarg, &uri, &match))
+ if (!filter_argument (optarg, &uri, &match, &ex.flags))
return 2;
break;
case opt_purpose:
@@ -406,10 +425,13 @@ p11_tool_extract (int argc,
/* If nothing that was useful to enumerate was specified, then bail */
if (uri == NULL && match == NULL) {
- p11_message ("no filter specified defaulting to 'ca-anchors'");
- filter_argument ("ca-anchors", &uri, &match);
+ p11_message ("no filter specified, defaulting to 'ca-anchors'");
+ filter_argument ("ca-anchors", &uri, &match, &ex.flags);
}
+ if (!validate_filter_and_format (&ex, format, match))
+ return 1;
+
if (uri && p11_kit_uri_any_unrecognized (uri))
p11_message ("uri contained unrecognized components, nothing will be extracted");
@@ -420,9 +442,7 @@ p11_tool_extract (int argc,
}
modules = p11_kit_registered_modules ();
-
- limit_purposes_if_necessary (&ex, format, match);
- limit_modules_if_necessary (modules, match);
+ limit_modules_if_necessary (modules, ex.flags);
iter = p11_kit_iter_new (uri);
diff --git a/tools/extract.h b/tools/extract.h
index dfd3a33..85405e5 100644
--- a/tools/extract.h
+++ b/tools/extract.h
@@ -46,11 +46,15 @@
enum {
/* These overlap with the flags in save.h, so start higher */
P11_EXTRACT_COMMENT = 1 << 10,
+ P11_EXTRACT_ANCHORS = 1 << 11,
+ P11_EXTRACT_BLACKLIST = 1 << 12,
+ P11_EXTRACT_COLLAPSE = 1 << 13,
};
typedef struct {
p11_dict *asn1_defs;
p11_dict *limit_to_purposes;
+ p11_dict *already_seen;
char *destination;
int flags;
diff --git a/tools/tests/test-extract.c b/tools/tests/test-extract.c
index 69ba764..c7382cd 100644
--- a/tools/tests/test-extract.c
+++ b/tools/tests/test-extract.c
@@ -171,17 +171,29 @@ teardown (CuTest *tc)
static CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
static CK_OBJECT_CLASS extension_class = CKO_X_CERTIFICATE_EXTENSION;
static CK_CERTIFICATE_TYPE x509_type = CKC_X_509;
+static CK_BBOOL truev = CK_TRUE;
-static CK_ATTRIBUTE cacert3_authority_attrs[] = {
+static CK_ATTRIBUTE cacert3_trusted[] = {
{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
{ CKA_CLASS, &certificate_class, sizeof (certificate_class) },
{ CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) },
{ CKA_LABEL, "Cacert3 Here", 11 },
{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+ { CKA_TRUSTED, &truev, sizeof (truev) },
{ CKA_ID, "ID1", 3 },
{ CKA_INVALID },
};
+static CK_ATTRIBUTE cacert3_distrusted[] = {
+ { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+ { CKA_CLASS, &certificate_class, sizeof (certificate_class) },
+ { CKA_CERTIFICATE_TYPE, &x509_type, sizeof (x509_type) },
+ { CKA_LABEL, "Another CaCert", 11 },
+ { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+ { CKA_X_DISTRUSTED, &truev, sizeof (truev) },
+ { CKA_INVALID },
+};
+
static CK_ATTRIBUTE certificate_filter[] = {
{ CKA_CLASS, &certificate_class, sizeof (certificate_class) },
{ CKA_INVALID },
@@ -213,7 +225,7 @@ test_info_simple_certificate (CuTest *tc)
CuAssertPtrNotNull (tc, test.ex.asn1_defs);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client);
p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
@@ -245,7 +257,7 @@ test_info_limit_purposes (CuTest *tc)
setup (tc);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client);
/* This should not match the above, with the stapled certificat ext */
@@ -270,7 +282,7 @@ test_info_invalid_purposes (CuTest *tc)
setup (tc);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_invalid);
p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
@@ -295,7 +307,7 @@ test_info_skip_non_certificate (CuTest *tc)
setup (tc);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
@@ -322,7 +334,7 @@ test_limit_to_purpose_match (CuTest *tc)
setup (tc);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client);
p11_extract_info_limit_purpose (&test.ex, P11_OID_SERVER_AUTH_STR);
@@ -346,7 +358,7 @@ test_limit_to_purpose_no_match (CuTest *tc)
setup (tc);
- mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
mock_module_add_object (MOCK_SLOT_ONE_ID, extension_eku_server_client);
p11_extract_info_limit_purpose (&test.ex, "3.3.3.3");
@@ -363,6 +375,146 @@ test_limit_to_purpose_no_match (CuTest *tc)
teardown (tc);
}
+static void
+test_duplicate_extract (CuTest *tc)
+{
+ CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+ CK_RV rv;
+
+ setup (tc);
+
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+
+ p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
+ p11_kit_iter_add_filter (test.iter, &certificate, 1);
+ p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_CANCEL, rv);
+
+ teardown (tc);
+}
+
+static void
+test_duplicate_collapse (CuTest *tc)
+{
+ CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+ CK_RV rv;
+
+ setup (tc);
+
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+
+ test.ex.flags = P11_EXTRACT_COLLAPSE;
+ p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
+ p11_kit_iter_add_filter (test.iter, &certificate, 1);
+ p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_CANCEL, rv);
+
+ teardown (tc);
+}
+
+static void
+test_trusted_match (CuTest *tc)
+{
+ CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+ CK_BBOOL boolv;
+ CK_RV rv;
+
+ setup (tc);
+
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+
+ test.ex.flags = P11_EXTRACT_ANCHORS;
+ p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
+ p11_kit_iter_add_filter (test.iter, &certificate, 1);
+ p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ if (!p11_attrs_find_bool (test.ex.attrs, CKA_TRUSTED, &boolv))
+ boolv = CK_FALSE;
+ CuAssertIntEquals (tc, CK_TRUE, boolv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_CANCEL, rv);
+
+ teardown (tc);
+}
+
+static void
+test_distrust_match (CuTest *tc)
+{
+ CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+ CK_BBOOL boolv;
+ CK_RV rv;
+
+ setup (tc);
+
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+
+ test.ex.flags = P11_EXTRACT_BLACKLIST;
+ p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
+ p11_kit_iter_add_filter (test.iter, &certificate, 1);
+ p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ if (!p11_attrs_find_bool (test.ex.attrs, CKA_X_DISTRUSTED, &boolv))
+ boolv = CK_FALSE;
+ CuAssertIntEquals (tc, CK_TRUE, boolv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_CANCEL, rv);
+
+ teardown (tc);
+}
+
+static void
+test_anytrust_match (CuTest *tc)
+{
+ CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+ CK_RV rv;
+
+ setup (tc);
+
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
+ mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+
+ test.ex.flags = P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST;
+ p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
+ p11_kit_iter_add_filter (test.iter, &certificate, 1);
+ p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ rv = p11_kit_iter_next (test.iter);
+ CuAssertIntEquals (tc, CKR_CANCEL, rv);
+
+ teardown (tc);
+}
+
int
main (void)
{
@@ -385,6 +537,11 @@ main (void)
SUITE_ADD_TEST (suite, test_info_skip_non_certificate);
SUITE_ADD_TEST (suite, test_limit_to_purpose_match);
SUITE_ADD_TEST (suite, test_limit_to_purpose_no_match);
+ SUITE_ADD_TEST (suite, test_duplicate_extract);
+ SUITE_ADD_TEST (suite, test_duplicate_collapse);
+ SUITE_ADD_TEST (suite, test_trusted_match);
+ SUITE_ADD_TEST (suite, test_distrust_match);
+ SUITE_ADD_TEST (suite, test_anytrust_match);
CuSuiteRun (suite);
CuSuiteSummary (suite, output);