]> git.saurik.com Git - apple/security.git/blob - SecurityTool/security.c
Security-58286.260.20.tar.gz
[apple/security.git] / SecurityTool / security.c
1 /*
2 * Copyright (c) 2003-2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * security.c
24 */
25
26 #include "security_tool.h"
27
28 #include "leaks.h"
29 #include "readline_cssm.h"
30
31 #include "cmsutil.h"
32 #include "db_commands.h"
33 #include "keychain_add.h"
34 #include "keychain_create.h"
35 #include "keychain_delete.h"
36 #include "keychain_list.h"
37 #include "keychain_lock.h"
38 #include "keychain_set_settings.h"
39 #include "keychain_show_info.h"
40 #include "keychain_unlock.h"
41 #include "keychain_recode.h"
42 #include "key_create.h"
43 #include "keychain_find.h"
44 #include "keychain_import.h"
45 #include "keychain_export.h"
46 #include "identity_find.h"
47 #include "identity_prefs.h"
48 #include "mds_install.h"
49 #include "trusted_cert_add.h"
50 #include "trusted_cert_dump.h"
51 #include "user_trust_enable.h"
52 #include "trust_settings_impexp.h"
53 #include "verify_cert.h"
54 #include "authz.h"
55 #include "smartcards.h"
56 #include "display_error_code.h"
57 #include "createFVMaster.h"
58 #include "smartcards.h"
59 #include "translocate.h"
60 #include "requirement.h"
61
62 #include <ctype.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67 #include <dispatch/dispatch.h>
68
69 #include <CoreFoundation/CFRunLoop.h>
70 #include <Security/SecBasePriv.h>
71 #include <Security/SecKeychainPriv.h>
72 #include <security_asn1/secerr.h>
73
74 /* Maximum length of an input line in interactive mode. */
75 #define MAX_LINE_LEN 4096
76 /* Maximum number of arguments on an input line in interactive mode. */
77 #define MAX_ARGS 32
78
79 /* Entry in commands array for a command. */
80 typedef struct command
81 {
82 const char *c_name; /* name of the command. */
83 command_func c_func; /* function to execute the command. */
84 const char *c_usage; /* usage sting for command. */
85 const char *c_help; /* help string for (or description of) command. */
86 } command;
87
88 /* The default prompt. */
89 const char *prompt_string = "security> ";
90
91 /* Forward declarations of static functions. */
92 static int help(int argc, char * const *argv);
93
94 /*
95 * The command array itself.
96 * Add commands here at will.
97 * Matching is done on a prefix basis. The first command in the array
98 * gets matched first.
99 */
100 const command commands[] =
101 {
102 { "help", help,
103 "[command ...]",
104 "Show all commands, or show usage for a command." },
105
106 { "list-keychains", keychain_list,
107 "[-d user|system|common|dynamic] [-s [keychain...]]\n"
108 " -d Use the specified preference domain\n"
109 " -s Set the search list to the specified keychains\n"
110 "With no parameters, display the search list.",
111 "Display or manipulate the keychain search list." },
112
113 { "list-smartcards", ctk_list,
114 "Display IDs of available smartcards.",
115 "Display available smartcards." },
116
117 { "default-keychain", keychain_default,
118 "[-d user|system|common|dynamic] [-s [keychain]]\n"
119 " -d Use the specified preference domain\n"
120 " -s Set the default keychain to the specified keychain\n"
121 "With no parameters, display the default keychain.",
122 "Display or set the default keychain." },
123
124 { "login-keychain", keychain_login,
125 "[-d user|system|common|dynamic] [-s [keychain]]\n"
126 " -d Use the specified preference domain\n"
127 " -s Set the login keychain to the specified keychain\n"
128 "With no parameters, display the login keychain.",
129 "Display or set the login keychain." },
130
131 { "create-keychain", keychain_create,
132 "[-P] [-p password] [keychains...]\n"
133 " -p Use \"password\" as the password for the keychains being created\n"
134 " -P Prompt the user for a password using the SecurityAgent\n"
135 "Use of the -p option is insecure",
136 "Create keychains and add them to the search list.",
137 },
138
139 { "delete-keychain", keychain_delete,
140 "[keychains...]",
141 "Delete keychains and remove them from the search list." },
142
143 { "lock-keychain", keychain_lock,
144 "[-a | keychain]\n"
145 " -a Lock all keychains",
146 "Lock the specified keychain."},
147
148 { "unlock-keychain", keychain_unlock,
149 "[-u] [-p password] [keychain]\n"
150 " -p Use \"password\" as the password to unlock the keychain\n"
151 " -u Do not use the password\n"
152 "Use of the -p option is insecure",
153 "Unlock the specified keychain."},
154
155 { "set-keychain-settings", keychain_set_settings,
156 "[-lu] [-t timeout] [keychain]\n"
157 " -l Lock keychain when the system sleeps\n"
158 " -u Lock keychain after timeout interval\n"
159 " -t Timeout in seconds (omitting this option specifies \"no timeout\")\n",
160 "Set settings for a keychain."},
161
162 { "set-keychain-password", keychain_set_password,
163 "[-o oldPassword] [-p newPassword] [keychain]\n"
164 " -o Old keychain password (if not provided, will prompt)\n"
165 " -p New keychain password (if not provided, will prompt)\n"
166 "Use of either the -o or -p options is insecure\n",
167 "Set password for a keychain."},
168
169 { "show-keychain-info", keychain_show_info,
170 "[keychain]",
171 "Show the settings for keychain." },
172
173 { "dump-keychain", keychain_dump,
174 "[-adir] [keychain...]\n"
175 " -a Dump access control list of items\n"
176 " -d Dump (decrypted) data of items\n"
177 " -i Interactive access control list editing mode\n"
178 " -r Dump the raw (encrypted) data of items",
179 "Dump the contents of one or more keychains." },
180
181 #ifndef NDEBUG
182 { "recode-keychain", keychain_recode,
183 "keychain_to_recode keychain_to_get_secrets_from",
184 "Recode a keychain to use the secrets from another one."},
185 #endif
186
187 { "create-keypair", key_create_pair,
188 "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-A|-T appPath] description\n"
189 " -a Use alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n"
190 " -s Specify the keysize in bits (default 512)\n"
191 " -f Make a key valid from the specified date\n"
192 " -t Make a key valid to the specified date\n"
193 " -d Make a key valid for the number of days specified from today\n"
194 " -k Use the specified keychain rather than the default\n"
195 " -A Allow any application to access this key without warning (insecure, not recommended!)\n"
196 " -T Specify an application which may access this key (multiple -T options are allowed)\n"
197 "If no options are provided, ask the user interactively.",
198 "Create an asymmetric key pair." },
199
200 #if 0
201 /* this was added in mb's integration of PR-3420772, but this is an unimplemented command */
202 { "create-csr", csr_create,
203 "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-A|-T appPath] description\n"
204 " -a Use alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n"
205 " -s Specify the keysize in bits (default 512)\n"
206 " -f Make a key valid from the specified date\n"
207 " -t Make a key valid to the specified date\n"
208 " -d Make a key valid for the number of days specified from today\n"
209 " -k Use the specified keychain rather than the default\n"
210 " -A Allow any application to access this key without warning (insecure, not recommended!)\n"
211 " -T Specify an application which may access this key (multiple -T options are allowed)\n"
212 "If no options are provided, ask the user interactively.",
213 "Create a certificate signing request." },
214 #endif
215
216 { "add-generic-password", keychain_add_generic_password,
217 "[-a account] [-s service] [-w password] [options...] [-A|-T appPath] [keychain]\n"
218 " -a Specify account name (required)\n"
219 " -c Specify item creator (optional four-character code)\n"
220 " -C Specify item type (optional four-character code)\n"
221 " -D Specify kind (default is \"application password\")\n"
222 " -G Specify generic attribute (optional)\n"
223 " -j Specify comment string (optional)\n"
224 " -l Specify label (if omitted, service name is used as default label)\n"
225 " -s Specify service name (required)\n"
226 " -p Specify password to be added (legacy option, equivalent to -w)\n"
227 " -w Specify password to be added\n"
228 " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
229 " -T Specify an application which may access this item (multiple -T options are allowed)\n"
230 " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
231 "\n"
232 "By default, the application which creates an item is trusted to access its data without warning.\n"
233 "You can remove this default access by explicitly specifying an empty app pathname: -T \"\"\n"
234 "If no keychain is specified, the password is added to the default keychain.\n"
235 "Use of the -p or -w options is insecure. Specify -w as the last option to be prompted.\n",
236 "Add a generic password item."},
237
238 { "add-internet-password", keychain_add_internet_password,
239 "[-a account] [-s server] [-w password] [options...] [-A|-T appPath] [keychain]\n"
240 " -a Specify account name (required)\n"
241 " -c Specify item creator (optional four-character code)\n"
242 " -C Specify item type (optional four-character code)\n"
243 " -d Specify security domain string (optional)\n"
244 " -D Specify kind (default is \"Internet password\")\n"
245 " -j Specify comment string (optional)\n"
246 " -l Specify label (if omitted, server name is used as default label)\n"
247 " -p Specify path string (optional)\n"
248 " -P Specify port number (optional)\n"
249 " -r Specify protocol (optional four-character SecProtocolType, e.g. \"http\", \"ftp \")\n"
250 " -s Specify server name (required)\n"
251 " -t Specify authentication type (as a four-character SecAuthenticationType, default is \"dflt\")\n"
252 " -w Specify password to be added\n"
253 " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
254 " -T Specify an application which may access this item (multiple -T options are allowed)\n"
255 " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
256 "\n"
257 "By default, the application which creates an item is trusted to access its data without warning.\n"
258 "You can remove this default access by explicitly specifying an empty app pathname: -T \"\"\n"
259 "If no keychain is specified, the password is added to the default keychain.\n"
260 "Use of the -p or -w options is insecure. Specify -w as the last option to be prompted.\n",
261 "Add an internet password item."},
262
263 { "add-certificates", keychain_add_certificates,
264 "[-k keychain] file...\n"
265 "If no keychain is specified, the certificates are added to the default keychain.",
266 "Add certificates to a keychain."},
267
268 { "find-generic-password", keychain_find_generic_password,
269 "[-a account] [-s service] [options...] [-g] [keychain...]\n"
270 " -a Match \"account\" string\n"
271 " -c Match \"creator\" (four-character code)\n"
272 " -C Match \"type\" (four-character code)\n"
273 " -D Match \"kind\" string\n"
274 " -G Match \"value\" string (generic attribute)\n"
275 " -j Match \"comment\" string\n"
276 " -l Match \"label\" string\n"
277 " -s Match \"service\" string\n"
278 " -g Display the password for the item found\n"
279 " -w Display only the password on stdout\n"
280 "If no keychains are specified to search, the default search list is used.",
281 "Find a generic password item."},
282
283 { "delete-generic-password", keychain_delete_generic_password,
284 "[-a account] [-s service] [options...] [keychain...]\n"
285 " -a Match \"account\" string\n"
286 " -c Match \"creator\" (four-character code)\n"
287 " -C Match \"type\" (four-character code)\n"
288 " -D Match \"kind\" string\n"
289 " -G Match \"value\" string (generic attribute)\n"
290 " -j Match \"comment\" string\n"
291 " -l Match \"label\" string\n"
292 " -s Match \"service\" string\n"
293 "If no keychains are specified to search, the default search list is used.",
294 "Delete a generic password item."},
295
296 { "set-generic-password-partition-list", keychain_set_generic_password_partition_list,
297 "[-a account] [-s service] [-S partition-list] [-k keychain password] [options...] [keychain]\n"
298 " -a Match \"account\" string\n"
299 " -c Match \"creator\" (four-character code)\n"
300 " -C Match \"type\" (four-character code)\n"
301 " -D Match \"kind\" string\n"
302 " -G Match \"value\" string (generic attribute)\n"
303 " -j Match \"comment\" string\n"
304 " -l Match \"label\" string\n"
305 " -s Match \"service\" string\n"
306 " -S Comma-separated list of allowed partition IDs\n"
307 " -k The password for the keychain (required)\n"
308 "If no keychains are specified to search, the default search list is used.\n"
309 "Use of the -k option is insecure. Omit it to be prompted.\n",
310 "Set the partition list of a generic password item."},
311
312 { "find-internet-password", keychain_find_internet_password,
313 "[-a account] [-s server] [options...] [-g] [keychain...]\n"
314 " -a Match \"account\" string\n"
315 " -c Match \"creator\" (four-character code)\n"
316 " -C Match \"type\" (four-character code)\n"
317 " -d Match \"securityDomain\" string\n"
318 " -D Match \"kind\" string\n"
319 " -j Match \"comment\" string\n"
320 " -l Match \"label\" string\n"
321 " -p Match \"path\" string\n"
322 " -P Match port number\n"
323 " -r Match \"protocol\" (four-character code)\n"
324 " -s Match \"server\" string\n"
325 " -t Match \"authenticationType\" (four-character code)\n"
326 " -g Display the password for the item found\n"
327 " -w Display only the password on stdout\n"
328 "If no keychains are specified to search, the default search list is used.",
329 "Find an internet password item."},
330
331 { "delete-internet-password", keychain_delete_internet_password,
332 "[-a account] [-s server] [options...] [keychain...]\n"
333 " -a Match \"account\" string\n"
334 " -c Match \"creator\" (four-character code)\n"
335 " -C Match \"type\" (four-character code)\n"
336 " -d Match \"securityDomain\" string\n"
337 " -D Match \"kind\" string\n"
338 " -j Match \"comment\" string\n"
339 " -l Match \"label\" string\n"
340 " -p Match \"path\" string\n"
341 " -P Match port number\n"
342 " -r Match \"protocol\" (four-character code)\n"
343 " -s Match \"server\" string\n"
344 " -t Match \"authenticationType\" (four-character code)\n"
345 "If no keychains are specified to search, the default search list is used.",
346 "Delete an internet password item."},
347
348 { "set-internet-password-partition-list", keychain_set_internet_password_partition_list,
349 "[-a account] [-s service] [-S partition-list] [-k keychain password] [options...] [keychain]\n"
350 " -a Match \"account\" string\n"
351 " -c Match \"creator\" (four-character code)\n"
352 " -C Match \"type\" (four-character code)\n"
353 " -d Match \"securityDomain\" string\n"
354 " -D Match \"kind\" string\n"
355 " -j Match \"comment\" string\n"
356 " -l Match \"label\" string\n"
357 " -p Match \"path\" string\n"
358 " -P Match port number\n"
359 " -r Match \"protocol\" (four-character code)\n"
360 " -s Match \"server\" string\n"
361 " -t Match \"authenticationType\" (four-character code)\n"
362 " -S Comma-separated list of allowed partition IDs\n"
363 " -k password for keychain (required)\n"
364
365 "If no keychains are specified to search, the default search list is used.\n"
366 "Use of the -k option is insecure. Omit it to be prompted.\n",
367 "Set the partition list of a internet password item."},
368
369 { "find-key", keychain_find_key,
370 "[options...] [keychain...]\n"
371 " -a Match \"application label\" string\n"
372 " -c Match \"creator\" (four-character code)\n"
373 " -d Match keys that can decrypt\n"
374 " -D Match \"description\" string\n"
375 " -e Match keys that can encrypt\n"
376 " -j Match \"comment\" string\n"
377 " -l Match \"label\" string\n"
378 " -r Match keys that can derive\n"
379 " -s Match keys that can sign\n"
380 " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
381 " -u Match keys that can unwrap\n"
382 " -v Match keys that can verify\n"
383 " -w Match keys that can wrap\n"
384
385 "If no keychains are specified to search, the default search list is used.",
386 "Find keys in the keychain"},
387
388 { "set-key-partition-list", keychain_set_key_partition_list,
389 "[options...] [keychain]\n"
390 " -a Match \"application label\" string\n"
391 " -c Match \"creator\" (four-character code)\n"
392 " -d Match keys that can decrypt\n"
393 " -D Match \"description\" string\n"
394 " -e Match keys that can encrypt\n"
395 " -j Match \"comment\" string\n"
396 " -l Match \"label\" string\n"
397 " -r Match keys that can derive\n"
398 " -s Match keys that can sign\n"
399 " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
400 " -u Match keys that can unwrap\n"
401 " -v Match keys that can verify\n"
402 " -w Match keys that can wrap\n"
403 " -S Comma-separated list of allowed partition IDs\n"
404 " -k password for keychain (required)\n"
405
406 "If no keychains are specified to search, the default search list is used.",
407 "Set the partition list of a key."},
408
409 { "find-certificate", keychain_find_certificate,
410 "[-a] [-c name] [-e emailAddress] [-m] [-p] [-Z] [keychain...]\n"
411 " -a Find all matching certificates, not just the first one\n"
412 " -c Match on \"name\" when searching (optional)\n"
413 " -e Match on \"emailAddress\" when searching (optional)\n"
414 " -m Show the email addresses in the certificate\n"
415 " -p Output certificate in pem format\n"
416 " -Z Print SHA-1 hash of the certificate\n"
417 "If no keychains are specified to search, the default search list is used.",
418 "Find a certificate item."},
419
420 { "find-identity", keychain_find_identity,
421 "[-p policy] [-s string] [-v] [keychain...]\n"
422 " -p Specify policy to evaluate (multiple -p options are allowed)\n"
423 " Supported policies: basic, ssl-client, ssl-server, smime, eap,\n"
424 " ipsec, ichat, codesigning, sys-default, sys-kerberos-kdc, macappstore, appleID\n"
425 " -s Specify optional policy-specific string (e.g. DNS hostname for SSL,\n"
426 " or RFC822 email address for S/MIME)\n"
427 " -v Show valid identities only (default is to show all identities)\n"
428 "If no keychains are specified to search, the default search list is used.",
429 "Find an identity (certificate + private key)."},
430
431 { "delete-certificate", keychain_delete_certificate,
432 "[-c name] [-Z hash] [-t] [keychain...]\n"
433 " -c Specify certificate to delete by its common name\n"
434 " -Z Specify certificate to delete by its SHA-1 hash value\n"
435 " -t Also delete user trust settings for this certificate\n"
436 "The certificate to be deleted must be uniquely specified either by a\n"
437 "string found in its common name, or by its SHA-1 hash.\n"
438 "If no keychains are specified to search, the default search list is used.",
439 "Delete a certificate from a keychain."},
440
441 { "delete-identity", keychain_delete_identity,
442 "[-c name] [-Z hash] [-t] [keychain...]\n"
443 " -c Specify certificate to delete by its common name\n"
444 " -Z Specify certificate to delete by its SHA-1 hash value\n"
445 " -t Also delete user trust settings for this identity certificate\n"
446 "The identity to be deleted must be uniquely specified either by a\n"
447 "string found in its common name, or by its SHA-1 hash.\n"
448 "If no keychains are specified to search, the default search list is used.",
449 "Delete an identity (certificate + private key) from a keychain."},
450
451 { "set-identity-preference", set_identity_preference,
452 "[-n] [-c identity] [-s service] [-u keyUsage] [-Z hash] [keychain...]\n"
453 " -n Specify no identity (clears existing preference for service)\n"
454 " -c Specify identity by common name of the certificate\n"
455 " -s Specify service (may be a URL, RFC822 email address, DNS host, or\n"
456 " other name) for which this identity is to be preferred\n"
457 " -u Specify key usage (optional) - see man page for values\n"
458 " -Z Specify identity by SHA-1 hash of certificate (optional)\n",
459 "Set the preferred identity to use for a service."},
460
461 { "get-identity-preference", get_identity_preference,
462 "[-s service] [-u keyUsage] [-p] [-c] [-Z] [keychain...]\n"
463 " -s Specify service (may be a URL, RFC822 email address, DNS host, or\n"
464 " other name)\n"
465 " -u Specify key usage (optional) - see man page for values\n"
466 " -p Output identity certificate in pem format\n"
467 " -c Print common name of the preferred identity certificate\n"
468 " -Z Print SHA-1 hash of the preferred identity certificate\n",
469 "Get the preferred identity to use for a service."},
470
471 { "create-db", db_create,
472 "[-ao0] [-g dl|cspdl] [-m mode] [name]\n"
473 " -a Turn off autocommit\n"
474 " -g Attach to \"guid\" rather than the AppleFileDL\n"
475 " -m Set the inital mode of the created db to \"mode\"\n"
476 " -o Force using openparams argument\n"
477 " -0 Force using version 0 openparams\n"
478 "If no name is provided, ask the user interactively.",
479 "Create a db using the DL." },
480
481 { "export" , keychain_export,
482 "[-k keychain] [-t type] [-f format] [-w] [-p] [-P passphrase] [-o outfile]\n"
483 " -k keychain to export items from\n"
484 " -t Type = certs|allKeys|pubKeys|privKeys|identities|all (Default: all)\n"
485 " -f Format = openssl|openssh1|openssh2|bsafe|pkcs7|pkcs8|pkcs12|pemseq|x509\n"
486 " ...default format is pemseq for aggregate, openssl for single\n"
487 " -w Private keys are wrapped\n"
488 " -p PEM encode the output\n"
489 " -P Specify wrapping passphrase immediately (default is secure passphrase via GUI)\n"
490 " -o Specify output file (default is stdout)\n"
491 "Use of the -P option is insecure\n",
492 "Export items from a keychain." },
493
494 { "import", keychain_import,
495 "inputfile [-k keychain] [-t type] [-f format] [-w] [-P passphrase] [options...]\n"
496 " -k Target keychain to import into\n"
497 " -t Type = pub|priv|session|cert|agg\n"
498 " -f Format = openssl|openssh1|openssh2|bsafe|raw|pkcs7|pkcs8|pkcs12|netscape|pemseq\n"
499 " -w Specify that private keys are wrapped and must be unwrapped on import\n"
500 " -x Specify that private keys are non-extractable after being imported\n"
501 " -P Specify wrapping passphrase immediately (default is secure passphrase via GUI)\n"
502 " -a Specify name and value of extended attribute (can be used multiple times)\n"
503 " -A Allow any application to access the imported key without warning (insecure, not recommended!)\n"
504 " -T Specify an application which may access the imported key (multiple -T options are allowed)\n"
505 "Use of the -P option is insecure\n",
506 "Import items into a keychain." },
507
508 { "export-smartcard" , ctk_export,
509 "[-i id] [-t type] [-e exportPath] \n"
510 " -i id of the smartcard to export (available IDs can be listed by list-smartcards\n"
511 " command, default: export/display all smartcards)\n"
512 " -t Type = certs|privKeys|identities|all (Default: all)\n"
513 " -e Specify path to export certificates and public keys. This option cannot be combined with -t option.\n",
514 "Export items from a smartcard." },
515
516 { "cms", cms_util,
517 "[-C|-D|-E|-S] [<options>]\n"
518 " -C create a CMS encrypted message\n"
519 " -D decode a CMS message\n"
520 " -E create a CMS enveloped message\n"
521 " -S create a CMS signed message\n"
522 "\n"
523 "Decoding options:\n"
524 " -c content use this detached content file\n"
525 " -h level generate email headers with info about CMS message\n"
526 " (output level >= 0)\n"
527 " -n suppress output of content\n"
528 "\n"
529 "Encoding options:\n"
530 " -r id,... create envelope for these recipients,\n"
531 " where id can be a certificate nickname or email address\n"
532 " -G include a signing time attribute\n"
533 " -H hash hash = MD2|MD4|MD5|SHA1|SHA256|SHA384|SHA512 (default: SHA1)\n"
534 " -N nick use certificate named \"nick\" for signing\n"
535 " -P include a SMIMECapabilities attribute\n"
536 " -T do not include content in CMS message\n"
537 " -Y nick include an EncryptionKeyPreference attribute with certificate\n"
538 " (use \"NONE\" to omit)\n"
539 " -Z hash find a certificate by subject key ID\n"
540 "\n"
541 "Common options:\n"
542 " -e envelope specify envelope file (valid with -D or -E)\n"
543 " -k keychain specify keychain to use\n"
544 " -i infile use infile as source of data (default: stdin)\n"
545 " -o outfile use outfile as destination of data (default: stdout)\n"
546 " -p password use password as key db password (default: prompt). Using -p is insecure\n"
547 " -s pass data a single byte at a time to CMS\n"
548 " -u certusage set type of certificate usage (default: certUsageEmailSigner)\n"
549 " -v print debugging information\n"
550 "\n"
551 "Cert usage codes:\n"
552 " 0 - certUsageSSLClient\n"
553 " 1 - certUsageSSLServer\n"
554 " 2 - certUsageSSLServerWithStepUp\n"
555 " 3 - certUsageSSLCA\n"
556 " 4 - certUsageEmailSigner\n"
557 " 5 - certUsageEmailRecipient\n"
558 " 6 - certUsageObjectSigner\n"
559 " 7 - certUsageUserCertImport\n"
560 " 8 - certUsageVerifyCA\n"
561 " 9 - certUsageProtectedObjectSigner\n"
562 " 10 - certUsageStatusResponder\n"
563 " 11 - certUsageAnyCA",
564 "Encode or decode CMS messages." },
565
566 { "install-mds" , mds_install,
567 "", /* no options */
568 "Install (or re-install) the MDS database." },
569
570 { "add-trusted-cert" , trusted_cert_add,
571 " [<options>] [certFile]\n"
572 " -d Add to admin cert store; default is user\n"
573 " -r resultType resultType = trustRoot|trustAsRoot|deny|unspecified;\n"
574 " default is trustRoot\n"
575 " -p policy Specify policy constraint (ssl, smime, codeSign, IPSec, iChat,\n"
576 " basic, swUpdate, pkgSign, pkinitClient, pkinitServer, eap)\n"
577 " -a appPath Specify application constraint\n"
578 " -s policyString Specify policy-specific string\n"
579 " -e allowedError Specify allowed error (certExpired, hostnameMismatch) or integer\n"
580 " -u keyUsage Specify key usage, an integer\n"
581 " -k keychain Specify keychain to which cert is added\n"
582 " -i settingsFileIn Input trust settings file; default is user domain\n"
583 " -o settingsFileOut Output trust settings file; default is user domain\n"
584 " certFile Certificate(s)",
585 "Add trusted certificate(s)." },
586
587 { "remove-trusted-cert" , trusted_cert_remove,
588 " [-d] [-D] [certFile]\n"
589 " -d Remove from admin cert store (default is user)\n"
590 " -D Remove default setting instead of per-cert setting\n"
591 " certFile Certificate(s)",
592 "Remove trusted certificate(s)." },
593
594 { "dump-trust-settings" , trusted_cert_dump,
595 " [-s] [-d]\n"
596 " -s Display trusted system certs (default is user)\n"
597 " -d Display trusted admin certs (default is user)\n",
598 "Display contents of trust settings." },
599
600 { "user-trust-settings-enable", user_trust_enable,
601 "[-d] [-e]\n"
602 " -d Disable user-level trust Settings\n"
603 " -e Enable user-level trust Settings\n"
604 "With no parameters, show current enable state of user-level trust settings.",
605 "Display or manipulate user-level trust settings." },
606
607 { "trust-settings-export", trust_settings_export,
608 " [-s] [-d] settings_file\n"
609 " -s Export system trust settings (default is user)\n"
610 " -d Export admin trust settings (default is user)\n",
611 "Export trust settings." },
612
613 { "trust-settings-import", trust_settings_import,
614 " [-d] settings_file\n"
615 " -d Import admin trust settings (default is user)\n",
616 "Import trust settings." },
617
618 { "verify-cert" , verify_cert,
619 " [<options>]\n"
620 " -c certFile Certificate to verify. Can be specified multiple times, leaf first.\n"
621 " -r rootCertFile Root Certificate. Can be specified multiple times.\n"
622 " -p policy Verify Policy (basic, ssl, smime, codeSign, IPSec, swUpdate, pkgSign,\n"
623 " eap, appleID, macappstore, timestamping); default is basic.\n"
624 " -C Set client policy to true. Default is server policy. (ssl, IPSec, eap)\n"
625 " -d date Set date and time to use when verifying certificate,\n"
626 " provided in the form of YYYY-MM-DD-hh:mm:ss (time optional) in GMT.\n"
627 " e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT\n"
628 " -k keychain Keychain. Can be specified multiple times. Default is default search list.\n"
629 " -n name Name to be verified. (ssl, IPSec, smime)\n"
630 " -N No keychain search list. (For backward compatibility, -n without a\n"
631 " subsequent name argument is interpreted as equivalent to -N.)\n"
632 " -L Local certificates only (do not try to fetch missing CA certs from net).\n"
633 " -l Leaf cert is a CA (normally an error, unless this option is given).\n"
634 " -e emailAddress Email address for smime policy. (Deprecated; use -n instead.)\n"
635 " -s sslHost SSL host name for ssl policy. (Deprecated; use -n instead.)\n"
636 " -q Quiet.\n"
637 " -R revCheckOption Perform revocation checking with one of the following options:\n"
638 " ocsp Check revocation status using OCSP method.\n"
639 " crl Check revocation status using CRL method.\n"
640 " require Require a positive response for successful verification.\n"
641 " offline Consult cached responses only (no network requests).\n"
642 " Can be specified multiple times; e.g. to enable revocation checking\n"
643 " via either OCSP or CRL methods and require a positive response, use\n"
644 " \"-R ocsp -R crl -R require\".\n",
645 "Verify certificate(s)." },
646
647 { "authorize" , authorize,
648 "[<options>] <right(s)...>\n"
649 " -u Allow user interaction.\n"
650 " -c Use login name and prompt for password.\n"
651 " -C login Use given login name and prompt for password.\n"
652 " -x Do NOT share -c/-C explicit credentials\n"
653 #ifndef NDEBUG
654 " -E Don't extend rights.\n"
655 #endif
656 " -p Allow returning partial rights.\n"
657 " -d Destroy acquired rights.\n"
658 " -P Pre-authorize rights only.\n"
659 " -l Operate authorizations in least privileged mode.\n"
660 " -i Internalize authref passed on stdin.\n"
661 " -e Externalize authref to stdout.\n"
662 " -w Wait until stdout is closed (to allow reading authref from pipe).\n"
663 "Extend rights flag is passed per default.",
664 "Perform authorization operations." },
665
666 { "authorizationdb" , authorizationdb,
667 "read <right-name>\n"
668 " authorizationdb remove <right-name>\n"
669 " authorizationdb write <right-name> [allow|deny|<rulename>]\n"
670 "If no rulename is specified, write will read a plist from stdin.\n"
671 " authorizationdb merge source [destination]\n"
672 "If no destination path is specified, merge will merge to /etc/authorization.\n"
673 " authorizationdb smartcard <enable|disable|status>\n"
674 "Enables/disables smartcard login support or report current status.",
675 "Make changes to the authorization policy database." },
676
677 { "execute-with-privileges" , execute_with_privileges,
678 "<program> [args...]\n"
679 "On success, stdin will be read and forwarded to the tool.",
680 "Execute tool with privileges." },
681
682 { "leaks", leaks,
683 "[-cycles] [-nocontext] [-nostacks] [-exclude symbol]\n"
684 " -cycles Use a stricter algorithm (\"man leaks\" for details)\n"
685 " -nocontext Withhold hex dumps of the leaked memory\n"
686 " -nostacks Don't show stack traces of leaked memory\n"
687 " -exclude Ignore leaks called from \"symbol\"\n"
688 "(Set the environment variable MallocStackLogging to get symbolic traces.)",
689 "Run /usr/bin/leaks on this process." },
690
691 { "error", display_error_code,
692 "<error code(s)...>\n"
693 "Display an error string for the given security-related error code.\n"
694 "The error can be in decimal or hex, e.g. 1234 or 0x1234. Multiple "
695 "errors can be separated by spaces.",
696 "Display a descriptive message for the given error code(s)." },
697
698 { "create-filevaultmaster-keychain", keychain_createMFV,
699 "[-p password] [keychain name]\n"
700 " -p Use \"password\" as the password for the keychain being created\n"
701 " -s Specify the keysize in bits (default 2048; 1024 & 4096 are allowed)\n"
702 "By default the keychain will be created in ~/Library/Keychains/.\n"
703 "Use of the -p option is insecure. Omit it to be prompted.\n",
704 "Create a keychain containing a key pair for FileVault recovery use."
705 },
706
707 { "smartcards" , smartcards,
708 "token [-l] [-e token] [-d token]\n"
709 " -l List disabled smartcard tokens]\n"
710 " -e token Enable specified token\n"
711 " -d token Disable specified token\n",
712 "Enable, disable or list disabled smartcard tokens." },
713
714 { "translocate-create", translocate_create,
715 "<path to translocate>\n"
716 "Displays the created path or the error returned.",
717 "Create a translocation point for the provided path" },
718
719 { "translocate-policy-check", translocate_policy,
720 "<path to check>\n"
721 "Displays \"Would translocate\" or \"Would not translocate\"\n"
722 "based on the current state of the path and system policy.",
723 "Check whether a path would be translocated." },
724
725 { "translocate-status-check", translocate_check,
726 "<path to check>\n"
727 "Displays \"TRANSLOCATED\" or \"NOT TRANSLOCATED\"\n"
728 "for the given path.",
729 "Check whether a path is translocated." },
730
731 { "translocate-original-path", translocate_original_path,
732 "<path to check>\n"
733 "If the provided path is translocated, display the original path\n"
734 "If the provided path is not translocated, display the passed in path",
735 "Find the original path for a translocated path." },
736
737 { "requirement-evaluate", requirement_evaluate,
738 "<requirements> [<DER certificate file> ...]\n"
739 "Evaluates the given requirement string against the given cert chain.",
740 "Evaluate a requirement against a cert chain." },
741
742 {}
743 };
744
745 /* Global variables. */
746 int do_quiet = 0;
747 int do_verbose = 0;
748
749 /* Return 1 if name matches command. */
750 static int
751 match_command(const char *command, const char *name)
752 {
753 return !strncmp(command, name, strlen(name));
754 }
755
756 /* The help command. */
757 static int
758 help(int argc, char * const *argv)
759 {
760 const command *c;
761
762 if (argc > 1)
763 {
764 char * const *arg;
765 for (arg = argv + 1; *arg; ++arg)
766 {
767 int found = 0;
768
769 for (c = commands; c->c_name; ++c)
770 {
771 if (match_command(c->c_name, *arg))
772 {
773 found = 1;
774 break;
775 }
776 }
777
778 if (found)
779 printf("Usage: %s %s\n", c->c_name, c->c_usage);
780 else
781 {
782 sec_error("%s: no such command: %s", argv[0], *arg);
783 return 1;
784 }
785 }
786 }
787 else
788 {
789 for (c = commands; c->c_name; ++c)
790 printf(" %-36s %s\n", c->c_name, c->c_help);
791 }
792
793 return 0;
794 }
795
796 /* States for split_line parser. */
797 typedef enum
798 {
799 SKIP_WS,
800 READ_ARG,
801 READ_ARG_ESCAPED,
802 QUOTED_ARG,
803 QUOTED_ARG_ESCAPED
804 } parse_state;
805
806 /* Split a line into multiple arguments and return them in *pargc and *pargv. */
807 static void
808 split_line(char *line, int *pargc, char * const **pargv)
809 {
810 static char *argvec[MAX_ARGS + 1];
811 int argc = 0;
812 char *ptr = line;
813 char *dst = line;
814 parse_state state = SKIP_WS;
815 int quote_ch = 0;
816
817 for (ptr = line; *ptr; ++ptr)
818 {
819 if (state == SKIP_WS)
820 {
821 if (isspace(*ptr))
822 continue;
823
824 if (*ptr == '"' || *ptr == '\'')
825 {
826 quote_ch = *ptr;
827 state = QUOTED_ARG;
828 argvec[argc] = dst;
829 continue; /* Skip the quote. */
830 }
831 else
832 {
833 state = READ_ARG;
834 argvec[argc] = dst;
835 }
836 }
837
838 if (state == READ_ARG)
839 {
840 if (*ptr == '\\')
841 {
842 state = READ_ARG_ESCAPED;
843 continue;
844 }
845 else if (isspace(*ptr))
846 {
847 /* 0 terminate each arg. */
848 *dst++ = '\0';
849 argc++;
850 state = SKIP_WS;
851 if (argc >= MAX_ARGS)
852 break;
853 }
854 else
855 *dst++ = *ptr;
856 }
857
858 if (state == QUOTED_ARG)
859 {
860 if (*ptr == '\\')
861 {
862 state = QUOTED_ARG_ESCAPED;
863 continue;
864 }
865 if (*ptr == quote_ch)
866 {
867 /* 0 terminate each arg. */
868 *dst++ = '\0';
869 argc++;
870 state = SKIP_WS;
871 if (argc >= MAX_ARGS)
872 break;
873 }
874 else
875 *dst++ = *ptr;
876 }
877
878 if (state == READ_ARG_ESCAPED)
879 {
880 *dst++ = *ptr;
881 state = READ_ARG;
882 }
883
884 if (state == QUOTED_ARG_ESCAPED)
885 {
886 *dst++ = *ptr;
887 state = QUOTED_ARG;
888 }
889 }
890
891 if (state != SKIP_WS)
892 {
893 /* Terminate last arg. */
894 *dst++ = '\0';
895 argc++;
896 }
897
898 /* Teminate arg vector. */
899 argvec[argc] = NULL;
900
901 *pargv = argvec;
902 *pargc = argc;
903 }
904
905 /* Print a (hopefully) useful usage message. */
906 static int
907 usage(void)
908 {
909 printf(
910 "Usage: %s [-h] [-i] [-l] [-p prompt] [-q] [-v] [command] [opt ...]\n"
911 " -i Run in interactive mode.\n"
912 " -l Run /usr/bin/leaks -nocontext before exiting.\n"
913 " -p Set the prompt to \"prompt\" (implies -i).\n"
914 " -q Be less verbose.\n"
915 " -v Be more verbose about what's going on.\n"
916 "%s commands are:\n", getprogname(), getprogname());
917 help(0, NULL);
918 return SHOW_USAGE_MESSAGE;
919 }
920
921 /* Execute a single command. */
922 static int
923 execute_command(int argc, char * const *argv)
924 {
925 const command *c;
926 int found = 0;
927
928 /* Nothing to do. */
929 if (argc == 0)
930 return 0;
931
932 for (c = commands; c->c_name; ++c)
933 {
934 if (match_command(c->c_name, argv[0]))
935 {
936 found = 1;
937 break;
938 }
939 }
940
941 if (found)
942 {
943 int result;
944
945 /* Reset getopt for command proc. */
946 optind = 1;
947 optreset = 1;
948
949 if (do_verbose)
950 {
951 int ix;
952
953 fprintf(stderr, "%s", c->c_name);
954 for (ix = 1; ix < argc; ++ix)
955 fprintf(stderr, " \"%s\"", argv[ix]);
956 fprintf(stderr, "\n");
957 }
958
959 result = c->c_func(argc, argv);
960 if (result == 2)
961 fprintf(stderr, "Usage: %s %s\n %s\n", c->c_name, c->c_usage, c->c_help);
962
963 return result;
964 }
965 else
966 {
967 sec_error("unknown command \"%s\"", argv[0]);
968 return 1;
969 }
970 }
971
972 static void
973 receive_notifications(void)
974 {
975 /* Run the CFRunloop to get any pending notifications. */
976 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource);
977 }
978
979
980 const char *
981 sec_errstr(int err)
982 {
983 const char *errString;
984 if (IS_SEC_ERROR(err))
985 errString = SECErrorString(err);
986 else
987 errString = cssmErrorString(err);
988 return errString;
989 }
990
991 void
992 sec_error(const char *msg, ...)
993 {
994 va_list args;
995
996 fprintf(stderr, "%s: ", getprogname());
997
998 va_start(args, msg);
999 vfprintf(stderr, msg, args);
1000 va_end(args);
1001
1002 fprintf(stderr, "\n");
1003 }
1004
1005 void
1006 sec_perror(const char *msg, int err)
1007 {
1008 sec_error("%s: %s", msg, sec_errstr(err));
1009 }
1010
1011 int
1012 main(int argc, char * const *argv)
1013 {
1014 int result = 0;
1015 int do_help = 0;
1016 int do_interactive = 0;
1017 int do_leaks = 0;
1018 int ch;
1019
1020
1021 /* Do getopt stuff for global options. */
1022 optind = 1;
1023 optreset = 1;
1024 while ((ch = getopt(argc, argv, "hilp:qvR")) != -1)
1025 {
1026 switch (ch)
1027 {
1028 case 'h':
1029 do_help = 1;
1030 break;
1031 case 'i':
1032 do_interactive = 1;
1033 break;
1034 case 'l':
1035 do_leaks = 1;
1036 break;
1037 case 'p':
1038 do_interactive = 1;
1039 prompt_string = optarg;
1040 break;
1041 case 'q':
1042 do_quiet = 1;
1043 break;
1044 case 'v':
1045 do_verbose = 1;
1046 break;
1047 case 'R':
1048 // "Recovery mode", do NOT ask security-checksystem to run when using keychain APIs
1049 // NOTE: this is a hidden option (not in the usage message)
1050 SecKeychainSystemKeychainCheckWouldDeadlock();
1051 break;
1052 case '?':
1053 default:
1054 return usage();
1055 }
1056 }
1057
1058 argc -= optind;
1059 argv += optind;
1060
1061 if (do_help)
1062 {
1063 /* Munge argc/argv so that argv[0] is something. */
1064 return help(argc + 1, argv - 1);
1065 }
1066 else if (argc > 0)
1067 {
1068 receive_notifications();
1069 result = execute_command(argc, argv);
1070 receive_notifications();
1071 }
1072 else if (do_interactive)
1073 {
1074 /* In interactive mode we just read commands and run them until readline returns NULL. */
1075
1076 /* Only show prompt string if stdin is a tty. */
1077 int show_prompt = isatty(0);
1078
1079 for (;;)
1080 {
1081 static char buffer[MAX_LINE_LEN];
1082 char * const *av, *input;
1083 int ac;
1084
1085 if (show_prompt)
1086 fprintf(stderr, "%s", prompt_string);
1087
1088 input = readline(buffer, MAX_LINE_LEN);
1089 if (!input)
1090 break;
1091
1092 split_line(input, &ac, &av);
1093 receive_notifications();
1094 result = execute_command(ac, av);
1095 receive_notifications();
1096 if (result == -1)
1097 {
1098 result = 0;
1099 break;
1100 }
1101
1102 if (result && ! do_quiet)
1103 {
1104 fprintf(stderr, "%s: returned %d\n", av[0], result);
1105 }
1106 }
1107 }
1108 else
1109 result = usage();
1110
1111 if (do_leaks)
1112 {
1113 char *const argvec[3] = { "leaks", "-nocontext", NULL };
1114 leaks(2, argvec);
1115 }
1116
1117 return result;
1118 }