2 * Copyright (c) 2013, Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 * * Redistributions in binary form must reproduce the
12 * above copyright notice, this list of conditions and
13 * the following disclaimer in the documentation and/or
14 * other materials provided with the distribution.
15 * * The names of contributors to this software may not be
16 * used to endorse or promote products derived from this
17 * software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 * Author: Stef Walter <stefw@redhat.com>
58 filter_argument (const char *optarg,
66 CK_OBJECT_CLASS vcertificate = CKO_CERTIFICATE;
67 CK_ULONG vauthority = 2;
68 CK_CERTIFICATE_TYPE vx509 = CKC_X_509;
70 CK_ATTRIBUTE certificate = { CKA_CLASS, &vcertificate, sizeof (vcertificate) };
71 CK_ATTRIBUTE authority = { CKA_CERTIFICATE_CATEGORY, &vauthority, sizeof (vauthority) };
72 CK_ATTRIBUTE x509 = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) };
74 if (strncmp (optarg, "pkcs11:", 7) == 0) {
76 p11_message ("only one pkcs11 uri filter may be specified");
79 *uri = p11_kit_uri_new ();
80 ret = p11_kit_uri_parse (optarg, P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE, *uri);
81 if (ret != P11_KIT_URI_OK) {
82 p11_message ("couldn't parse pkcs11 uri filter: %s", optarg);
88 if (strcmp (optarg, "ca-anchors") == 0) {
89 attrs = p11_attrs_build (NULL, &certificate, &authority, &x509, NULL);
90 *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_COLLAPSE;
92 } else if (strcmp (optarg, "trust-policy") == 0) {
93 attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
94 *flags |= P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE;
96 } else if (strcmp (optarg, "blacklist") == 0) {
97 attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
98 *flags |= P11_EXTRACT_BLACKLIST | P11_EXTRACT_COLLAPSE;
100 } else if (strcmp (optarg, "certificates") == 0) {
101 attrs = p11_attrs_build (NULL, &certificate, &x509, NULL);
102 *flags |= P11_EXTRACT_COLLAPSE;
105 p11_message ("unsupported or unrecognized filter: %s", optarg);
109 if (*match != NULL) {
110 p11_message ("a conflicting filter has already been specified");
111 p11_attrs_free (attrs);
120 is_valid_oid_rough (const char *string)
124 len = strlen (string);
126 /* Rough check if a valid OID */
127 return (strspn (string, "0123456789.") == len &&
128 !strstr (string, "..") && string[0] != '\0' && string[0] != '.' &&
129 string[len - 1] != '.');
133 purpose_argument (const char *optarg,
134 p11_extract_info *ex)
138 if (strcmp (optarg, "server-auth") == 0) {
139 oid = P11_OID_SERVER_AUTH_STR;
140 } else if (strcmp (optarg, "client-auth") == 0) {
141 oid = P11_OID_CLIENT_AUTH_STR;
142 } else if (strcmp (optarg, "email-protection") == 0 || strcmp (optarg, "email") == 0) {
143 oid = P11_OID_EMAIL_PROTECTION_STR;
144 } else if (strcmp (optarg, "code-signing") == 0) {
145 oid = P11_OID_CODE_SIGNING_STR;
146 } else if (strcmp (optarg, "ipsec-end-system") == 0) {
147 oid = P11_OID_IPSEC_END_SYSTEM_STR;
148 } else if (strcmp (optarg, "ipsec-tunnel") == 0) {
149 oid = P11_OID_IPSEC_TUNNEL_STR;
150 } else if (strcmp (optarg, "ipsec-user") == 0) {
151 oid = P11_OID_IPSEC_USER_STR;
152 } else if (strcmp (optarg, "time-stamping") == 0) {
153 oid = P11_OID_TIME_STAMPING_STR;
154 } else if (is_valid_oid_rough (optarg)) {
157 p11_message ("unsupported or unregonized purpose: %s", optarg);
161 p11_extract_info_limit_purpose (ex, oid);
166 format_argument (const char *optarg,
167 p11_extract_func *func)
172 * Certain formats do not support expressive trust information.
173 * So the caller should limit the supported purposes when asking
174 * for trust information.
177 static const struct {
179 p11_extract_func func;
181 { "x509-file", p11_extract_x509_file, },
182 { "x509-directory", p11_extract_x509_directory, },
183 { "pem-bundle", p11_extract_pem_bundle, },
184 { "pem-directory", p11_extract_pem_directory },
185 { "java-cacerts", p11_extract_jks_cacerts },
186 { "openssl-bundle", p11_extract_openssl_bundle },
187 { "openssl-directory", p11_extract_openssl_directory },
192 p11_message ("a format was already specified");
196 for (i = 0; formats[i].format != NULL; i++) {
197 if (strcmp (optarg, formats[i].format) == 0) {
198 *func = formats[i].func;
204 p11_message ("unsupported or unrecognized format: %s", optarg);
212 limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules,
219 * We only "believe" the CKA_TRUSTED and CKA_X_DISTRUSTED attributes
220 * we get from modules explicitly marked as containing trust-policy.
223 if ((flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST)) == 0)
226 /* Count the number of modules */
227 for (out = 0; modules[out] != NULL; out++);
232 /* TODO: This logic will move once we merge our p11-kit managed code */
233 for (i = 0, out = 0; modules[i] != NULL; i++) {
234 string = p11_kit_registered_option (modules[i], "trust-policy");
235 if (string && strcmp (string, "yes") == 0)
236 modules[out++] = modules[i];
237 else if (string && strcmp (string, "no") != 0)
238 p11_message ("skipping module with invalid 'trust-policy' setting: %s", string);
243 p11_message ("no modules containing trust policy are registered");
247 validate_filter_and_format (p11_extract_info *ex,
248 p11_extract_func func,
254 * These are the extract functions that contain purpose information.
255 * If we're being asked to export anchors, and the extract function does
256 * not support, and the caller has not specified a purpose, then add a
257 * default purpose to limit to.
260 static p11_extract_func supports_trust_policy[] = {
261 p11_extract_openssl_bundle,
262 p11_extract_openssl_directory,
266 for (i = 0; supports_trust_policy[i] != NULL; i++) {
267 if (func == supports_trust_policy[i])
271 if ((ex->flags & P11_EXTRACT_ANCHORS) &&
272 (ex->flags & P11_EXTRACT_BLACKLIST)) {
274 * If we're extracting *both* anchors and blacklist, then we must have
275 * a format that can represent the different types of information.
278 p11_message ("format does not support trust policy");
281 } else if (ex->flags & P11_EXTRACT_ANCHORS) {
284 * If we're extracting anchors, then we must have either limited the
285 * purposes, or have a format that can represent multiple purposes.
288 if (!ex->limit_to_purposes) {
289 p11_message ("format does not support multiple purposes, defaulting to 'server-auth'");
290 p11_extract_info_limit_purpose (ex, P11_OID_SERVER_AUTH_STR);
298 p11_tool_extract (int argc,
301 p11_extract_func format = NULL;
302 CK_FUNCTION_LIST_PTR *modules;
322 struct option options[] = {
323 { "filter", required_argument, NULL, opt_filter },
324 { "format", required_argument, NULL, opt_format },
325 { "purpose", required_argument, NULL, opt_purpose },
326 { "overwrite", no_argument, NULL, opt_overwrite },
327 { "comment", no_argument, NULL, opt_comment },
328 { "verbose", no_argument, NULL, opt_verbose },
329 { "quiet", no_argument, NULL, opt_quiet },
330 { "help", no_argument, NULL, opt_help },
334 p11_tool_desc usages[] = {
335 { 0, "usage: p11-kit extract --format=<output> <destination>" },
337 "filter of what to export\n"
338 " ca-anchors certificate anchors (default)\n"
339 " blacklist blacklisted certificates\n"
340 " trust-policy anchors and blacklist\n"
341 " certificates all certificates\n"
342 " pkcs11:object=xx a PKCS#11 URI",
346 "format to extract to\n"
347 " x509-file DER X.509 certificate file\n"
348 " x509-directory directory of X.509 certificates\n"
349 " pem-bundle file containing multiple PEM blocks\n"
350 " pem-directory directory of PEM files\n"
351 " openssl-bundle OpenSSL specific PEM bundle\n"
352 " openssl-directory directory of OpenSSL specific files\n"
353 " java-cacerts java keystore cacerts file",
357 "limit to certificates usable for the purpose\n"
358 " server-auth for authenticating servers\n"
359 " client-auth for authenticating clients\n"
360 " email for email protection\n"
361 " code-signing for authenticating signed code\n"
362 " 1.2.3.4.5... an arbitrary object id",
365 { opt_overwrite, "overwrite output file or directory" },
366 { opt_comment, "add comments to bundles if possible" },
367 { opt_verbose, "show verbose debug output", },
368 { opt_quiet, "supress command output", },
375 p11_extract_info_init (&ex);
377 while ((opt = p11_tool_getopt (argc, argv, options)) != -1) {
384 ex.flags |= P11_SAVE_OVERWRITE;
387 ex.flags |= P11_EXTRACT_COMMENT;
390 if (!filter_argument (optarg, &uri, &match, &ex.flags))
394 if (!purpose_argument (optarg, &ex))
398 if (!format_argument (optarg, &format))
402 p11_tool_usage (usages, options);
407 assert_not_reached ();
416 p11_message ("specify one destination file or directory");
419 ex.destination = argv[0];
422 p11_message ("no output format specified");
426 /* If nothing that was useful to enumerate was specified, then bail */
427 if (uri == NULL && match == NULL) {
428 p11_message ("no filter specified, defaulting to 'ca-anchors'");
429 filter_argument ("ca-anchors", &uri, &match, &ex.flags);
432 if (!validate_filter_and_format (&ex, format, match))
435 if (uri && p11_kit_uri_any_unrecognized (uri))
436 p11_message ("uri contained unrecognized components, nothing will be extracted");
438 rv = p11_kit_initialize_registered ();
440 p11_message ("couldn't initialize registered modules: %s", p11_kit_strerror (rv));
444 modules = p11_kit_registered_modules ();
445 limit_modules_if_necessary (modules, ex.flags);
447 iter = p11_kit_iter_new (uri);
449 p11_kit_iter_add_callback (iter, p11_extract_info_load_filter, &ex, NULL);
450 p11_kit_iter_add_filter (iter, match, p11_attrs_count (match));
452 p11_kit_iter_begin (iter, modules);
454 ret = (format) (iter, &ex) ? 0 : 1;
456 p11_extract_info_cleanup (&ex);
457 p11_kit_iter_free (iter);
458 p11_kit_uri_free (uri);
461 p11_kit_finalize_registered ();