xref: /titanic_52/usr/src/cmd/cmd-crypto/elfsign/elfsign.c (revision 4201a95e0468170d576f82c3aa63afecf718497a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Developer command for adding the signature section to an ELF object
29  * PSARC 2001/488
30  *
31  * DEBUG Information:
32  * This command uses the cryptodebug() function from libcryptoutil.
33  * Set SUNW_CRYPTO_DEBUG to stderr or syslog for all debug to go to auth.debug
34  */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <limits.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <libintl.h>
46 #include <locale.h>
47 #include <errno.h>
48 #include <strings.h>
49 #include <langinfo.h>
50 
51 #include <cryptoutil.h>
52 #include <sys/crypto/elfsign.h>
53 #include <libelfsign.h>
54 
55 #include <kmfapi.h>
56 
57 #define	SIGN		"sign"
58 #define	SIGN_OPTS	"ac:e:F:k:P:T:v"
59 #define	VERIFY		"verify"
60 #define	VERIFY_OPTS	"c:e:v"
61 #define	REQUEST		"request"
62 #define	REQUEST_OPTS	"i:k:r:T:"
63 #define	LIST		"list"
64 #define	LIST_OPTS	"c:e:f:"
65 
66 enum cmd_e {
67 	ES_SIGN,
68 	ES_VERIFY,
69 	ES_REQUEST,
70 	ES_LIST
71 };
72 
73 enum field_e {
74 	FLD_UNKNOWN,
75 	FLD_SUBJECT,
76 	FLD_ISSUER,
77 	FLD_FORMAT,
78 	FLD_SIGNER,
79 	FLD_TIME
80 };
81 
82 #define	MIN_ARGS	3	/* The minimum # args to do anything */
83 #define	ES_DEFAULT_KEYSIZE 1024
84 
85 static struct {
86 	enum cmd_e	cmd;	/* sub command: sign | verify | request */
87 	char	*cert;		/* -c <certificate_file> | */
88 				/* -r <certificate_request_file> */
89 	char	**elfobj;	/* -e <elf_object> */
90 	int	elfcnt;
91 	enum ES_ACTION	es_action;
92 	ELFsign_t	ess;	/* libelfsign opaque "state" */
93 	int	extracnt;
94 	enum field_e	field;	/* -f <field> */
95 	char internal_req;	/* Sun internal certificate request */
96 	char	*pinpath;	/* -P <pin> */
97 	char	*privpath;	/* -k <private_key> */
98 	char	*token_label;	/* -T <token_label> */
99 	boolean_t verbose;	/* chatty output */
100 } cmd_info;
101 
102 enum ret_e {
103 	EXIT_OKAY,
104 	EXIT_INVALID_ARG,
105 	EXIT_VERIFY_FAILED,
106 	EXIT_CANT_OPEN_ELF_OBJECT,
107 	EXIT_BAD_CERT,
108 	EXIT_BAD_PRIVATEKEY,
109 	EXIT_SIGN_FAILED,
110 	EXIT_VERIFY_FAILED_UNSIGNED,
111 	EXIT_CSR_FAILED,
112 	EXIT_MEMORY_ERROR
113 };
114 
115 struct field_s {
116 	char	*name;
117 	enum field_e	field;
118 } fields[] = {
119 	{ "subject", FLD_SUBJECT },
120 	{ "issuer", FLD_ISSUER },
121 	{ "format", FLD_FORMAT },
122 	{ "signer", FLD_SIGNER },
123 	{ "time", FLD_TIME },
124 	NULL, 0
125 };
126 
127 typedef enum ret_e ret_t;
128 
129 static void usage(void);
130 static ret_t getelfobj(char *);
131 static char *getpin(void);
132 static ret_t do_sign(char *);
133 static ret_t do_verify(char *);
134 static ret_t do_cert_request(char *);
135 static ret_t do_gen_esa(char *);
136 static ret_t do_list(char *);
137 static void es_error(const char *fmt, ...);
138 static char *time_str(time_t t);
139 static void sig_info_print(struct ELFsign_sig_info *esip);
140 
141 int
142 main(int argc, char **argv)
143 {
144 	extern char *optarg;
145 	char *scmd = NULL;
146 	char *opts;		/* The set of flags for cmd */
147 	int errflag = 0;	/* We had an options parse error */
148 	char c;			/* current getopts flag */
149 	ret_t (*action)(char *);	/* Function pointer for the action */
150 	ret_t ret;
151 
152 	(void) setlocale(LC_ALL, "");
153 #if !defined(TEXT_DOMAIN)	/* Should be defiend by cc -D */
154 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
155 #endif
156 	(void) textdomain(TEXT_DOMAIN);
157 
158 	cryptodebug_init("elfsign");
159 
160 	if (argc < MIN_ARGS) {
161 		es_error(gettext("invalid number of arguments"));
162 		usage();
163 		return (EXIT_INVALID_ARG);
164 	}
165 
166 	scmd = argv[1];
167 	cmd_info.cert = NULL;
168 	cmd_info.elfobj = NULL;
169 	cmd_info.elfcnt = 0;
170 	cmd_info.es_action = ES_GET;
171 	cmd_info.ess = NULL;
172 	cmd_info.extracnt = 0;
173 	cmd_info.field = FLD_UNKNOWN;
174 	cmd_info.internal_req = '\0';
175 	cmd_info.pinpath = NULL;
176 	cmd_info.privpath = NULL;
177 	cmd_info.token_label = NULL;
178 	cmd_info.verbose = B_FALSE;
179 
180 	if (strcmp(scmd, SIGN) == 0) {
181 		cmd_info.cmd = ES_SIGN;
182 		opts = SIGN_OPTS;
183 		cryptodebug("cmd=sign opts=%s", opts);
184 		action = do_sign;
185 		cmd_info.es_action = ES_UPDATE_RSA_SHA1;
186 	} else if (strcmp(scmd, VERIFY) == 0) {
187 		cmd_info.cmd = ES_VERIFY;
188 		opts = VERIFY_OPTS;
189 		cryptodebug("cmd=verify opts=%s", opts);
190 		action = do_verify;
191 	} else if (strcmp(scmd, REQUEST) == 0) {
192 		cmd_info.cmd = ES_REQUEST;
193 		opts = REQUEST_OPTS;
194 		cryptodebug("cmd=request opts=%s", opts);
195 		action = do_cert_request;
196 	} else if (strcmp(scmd, LIST) == 0) {
197 		cmd_info.cmd = ES_LIST;
198 		opts = LIST_OPTS;
199 		cryptodebug("cmd=list opts=%s", opts);
200 		action = do_list;
201 	} else {
202 		es_error(gettext("Unknown sub-command: %s"),
203 		    scmd);
204 		usage();
205 		return (EXIT_INVALID_ARG);
206 	}
207 
208 	/*
209 	 * Note:  There is no need to check that optarg isn't NULL
210 	 *	  because getopt does that for us.
211 	 */
212 	while (!errflag && (c = getopt(argc - 1, argv + 1, opts)) != EOF) {
213 		if (strchr("ceFihkPTr", c) != NULL)
214 			cryptodebug("c=%c, '%s'", c, optarg);
215 		else
216 			cryptodebug("c=%c", c);
217 
218 		switch (c) {
219 		case 'a':
220 			/* not a normal sign operation, change the action */
221 			cmd_info.es_action = ES_GET;
222 			action = do_gen_esa;
223 			break;
224 		case 'c':
225 			cmd_info.cert = optarg;
226 			break;
227 		case 'e':
228 			cmd_info.elfcnt++;
229 			cmd_info.elfobj = (char **)realloc(cmd_info.elfobj,
230 			    sizeof (char *) * cmd_info.elfcnt);
231 			if (cmd_info.elfobj == NULL) {
232 				es_error(gettext(
233 				    "Too many elf objects specified."));
234 				return (EXIT_INVALID_ARG);
235 			}
236 			cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg;
237 			break;
238 		case 'f':
239 			{
240 				struct field_s	*fp;
241 				cmd_info.field = FLD_UNKNOWN;
242 				for (fp = fields; fp->name != NULL; fp++) {
243 					if (strcasecmp(optarg, fp->name) == 0) {
244 						cmd_info.field = fp->field;
245 						break;
246 					}
247 				}
248 				if (cmd_info.field == FLD_UNKNOWN) {
249 					cryptodebug("Invalid field option");
250 					errflag++;
251 				}
252 			}
253 			break;
254 		case 'F':
255 			if (strcasecmp(optarg, ES_FMT_RSA_MD5_SHA1) == 0)
256 				cmd_info.es_action = ES_UPDATE_RSA_MD5_SHA1;
257 			else if (strcasecmp(optarg, ES_FMT_RSA_SHA1) == 0)
258 				cmd_info.es_action = ES_UPDATE_RSA_SHA1;
259 			else {
260 				cryptodebug("Invalid format option");
261 				errflag++;
262 			}
263 			break;
264 		case 'i':	 /* Undocumented internal Sun use only */
265 			cmd_info.internal_req = *optarg;
266 			break;
267 		case 'k':
268 			cmd_info.privpath = optarg;
269 			if (cmd_info.token_label != NULL ||
270 			    cmd_info.pinpath != NULL)
271 				errflag++;
272 			break;
273 		case 'P':
274 			cmd_info.pinpath = optarg;
275 			if (cmd_info.privpath != NULL)
276 				errflag++;
277 			break;
278 		case 'r':
279 			cmd_info.cert = optarg;
280 			break;
281 		case 'T':
282 			cmd_info.token_label = optarg;
283 			if (cmd_info.privpath != NULL)
284 				errflag++;
285 			break;
286 		case 'v':
287 			cmd_info.verbose = B_TRUE;
288 			break;
289 		default:
290 			errflag++;
291 		}
292 	}
293 
294 	optind++;	/* we skipped over subcommand */
295 	cmd_info.extracnt = argc - optind;
296 
297 	if (cmd_info.extracnt != 0 &&
298 	    cmd_info.cmd != ES_SIGN && cmd_info.cmd != ES_VERIFY) {
299 		cryptodebug("Extra arguments, optind=%d, argc=%d",
300 		    optind, argc);
301 		errflag++;
302 	}
303 
304 	switch (cmd_info.cmd) {
305 	case ES_VERIFY:
306 		if (cmd_info.elfcnt + argc - optind == 0) {
307 			cryptodebug("Missing elfobj");
308 			errflag++;
309 		}
310 		break;
311 
312 	case ES_SIGN:
313 		if (((cmd_info.privpath == NULL) &&
314 		    (cmd_info.token_label == NULL)) ||
315 		    (cmd_info.cert == NULL) ||
316 		    (cmd_info.elfcnt + argc - optind == 0)) {
317 			cryptodebug("Missing privpath|token_label/cert/elfobj");
318 			errflag++;
319 		}
320 		break;
321 
322 	case ES_REQUEST:
323 		if (((cmd_info.privpath == NULL) &&
324 		    (cmd_info.token_label == NULL)) ||
325 		    (cmd_info.cert == NULL)) {
326 			cryptodebug("Missing privpath|token_label/certreq");
327 			errflag++;
328 		}
329 		break;
330 	case ES_LIST:
331 		if ((cmd_info.cert != NULL) == (cmd_info.elfcnt > 0)) {
332 			cryptodebug("Neither or both of cert/elfobj");
333 			errflag++;
334 		}
335 		break;
336 	}
337 
338 	if (errflag) {
339 		usage();
340 		return (EXIT_INVALID_ARG);
341 	}
342 
343 	switch (cmd_info.cmd) {
344 	case ES_REQUEST:
345 	case ES_LIST:
346 		ret = action(NULL);
347 		break;
348 	default:
349 		{
350 		int i;
351 		ret_t	iret;
352 
353 		ret = EXIT_OKAY;
354 		iret = EXIT_OKAY;
355 		for (i = 0; i < cmd_info.elfcnt &&
356 		    (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
357 			iret = action(cmd_info.elfobj[i]);
358 			if (iret > ret)
359 				ret = iret;
360 		}
361 		for (i = optind; i < argc &&
362 		    (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
363 			iret = action(argv[i]);
364 			if (iret > ret)
365 				ret = iret;
366 		}
367 		break;
368 		}
369 	}
370 
371 	if (cmd_info.elfobj != NULL)
372 		free(cmd_info.elfobj);
373 
374 	return (ret);
375 }
376 
377 
378 static void
379 usage(void)
380 {
381 /* BEGIN CSTYLED */
382 	(void) fprintf(stderr, gettext(
383  "usage:\n"
384  "\telfsign sign [-a] [-v] [-e <elf_object>] -c <certificate_file>\n"
385  "\t\t[-F <format>] -k <private_key_file> [elf_object]..."
386  "\n"
387  "\telfsign sign [-a] [-v] [-e <elf_object>] -c <certificate_file>\n"
388  "\t\t[-F <format>] -T <token_label> [-P <pin_file>] [elf_object]..."
389  "\n\n"
390  "\telfsign verify [-v] [-c <certificate_file>] [-e <elf_object>]\n"
391  "\t\t[elf_object]..."
392  "\n\n"
393  "\telfsign request -r <certificate_request_file> -k <private_key_file>"
394  "\n"
395  "\telfsign request -r <certificate_request_file> -T <token_label>"
396  "\n\n"
397  "\telfsign list -f field -c <certificate_file>"
398  "\n"
399  "\telfsign list -f field -e <elf_object>"
400  "\n"));
401 /* END CSTYLED */
402 }
403 
404 static ret_t
405 getelfobj(char *elfpath)
406 {
407 	ELFsign_status_t estatus;
408 	ret_t	ret = EXIT_SIGN_FAILED;
409 
410 	estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess));
411 	switch (estatus) {
412 	case ELFSIGN_SUCCESS:
413 	case ELFSIGN_RESTRICTED:
414 		ret = EXIT_OKAY;
415 		break;
416 	case ELFSIGN_INVALID_ELFOBJ:
417 		es_error(gettext(
418 		    "Unable to open %s as an ELF object."),
419 		    elfpath);
420 		ret = EXIT_CANT_OPEN_ELF_OBJECT;
421 		break;
422 	default:
423 		es_error(gettext("unexpected failure: %d"), estatus);
424 		if (cmd_info.cmd == ES_SIGN) {
425 			ret = EXIT_SIGN_FAILED;
426 		} else if (cmd_info.cmd == ES_VERIFY) {
427 			ret = EXIT_VERIFY_FAILED;
428 		}
429 	}
430 
431 	return (ret);
432 }
433 
434 static ret_t
435 setcertpath(void)
436 {
437 	ELFsign_status_t estatus;
438 	ret_t	ret = EXIT_SIGN_FAILED;
439 
440 	if (cmd_info.cert == NULL)
441 		return (EXIT_OKAY);
442 	estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert);
443 	switch (estatus) {
444 	case ELFSIGN_SUCCESS:
445 		ret = EXIT_OKAY;
446 		break;
447 	case ELFSIGN_INVALID_CERTPATH:
448 		if (cmd_info.cert != NULL) {
449 			es_error(gettext("Unable to open %s as a certificate."),
450 			    cmd_info.cert);
451 		}
452 		ret = EXIT_BAD_CERT;
453 		break;
454 	default:
455 		es_error(gettext("unusable certificate: %s"), cmd_info.cert);
456 		if (cmd_info.cmd == ES_SIGN) {
457 			ret = EXIT_SIGN_FAILED;
458 		} else if (cmd_info.cmd == ES_VERIFY) {
459 			ret = EXIT_VERIFY_FAILED;
460 		}
461 	}
462 
463 	return (ret);
464 }
465 
466 /*
467  * getpin - return pointer to token PIN in static storage
468  */
469 static char *
470 getpin(void)
471 {
472 	static char	pinbuf[PASS_MAX + 1];
473 	char	*pp;
474 	FILE	*pinfile;
475 
476 	if (cmd_info.pinpath == NULL)
477 		return (getpassphrase(
478 		    gettext("Enter PIN for PKCS#11 token: ")));
479 	if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) {
480 		es_error(gettext("failed to open %s."),
481 		    cmd_info.pinpath);
482 		return (NULL);
483 	}
484 
485 	pp = fgets(pinbuf, sizeof (pinbuf), pinfile);
486 	(void) fclose(pinfile);
487 	if (pp == NULL) {
488 		es_error(gettext("failed to read PIN from %s."),
489 		    cmd_info.pinpath);
490 		return (NULL);
491 	}
492 	pp = &pinbuf[strlen(pinbuf) - 1];
493 	if (*pp == '\n')
494 		*pp = '\0';
495 	return (pinbuf);
496 }
497 
498 /*
499  * Add the .SUNW_signature sections for the ELF signature
500  */
501 static ret_t
502 do_sign(char *object)
503 {
504 	ret_t 	ret;
505 	ELFsign_status_t	elfstat;
506 	struct filesignatures	*fssp = NULL;
507 	size_t fs_len;
508 	uchar_t sig[SIG_MAX_LENGTH];
509 	size_t	sig_len = SIG_MAX_LENGTH;
510 	uchar_t	hash[SIG_MAX_LENGTH];
511 	size_t	hash_len = SIG_MAX_LENGTH;
512 	ELFCert_t	cert = NULL;
513 	char	*dn;
514 	size_t	dn_len;
515 
516 	cryptodebug("do_sign");
517 	if ((ret = getelfobj(object)) != EXIT_OKAY)
518 		return (ret);
519 
520 	if (cmd_info.token_label &&
521 	    !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) {
522 		es_error(gettext("Unable to access token: %s"),
523 		    cmd_info.token_label);
524 		ret = EXIT_SIGN_FAILED;
525 		goto cleanup;
526 	}
527 
528 	if ((ret = setcertpath()) != EXIT_OKAY)
529 		goto cleanup;
530 
531 	if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
532 	    cmd_info.es_action)) {
533 		es_error(gettext("Unable to load certificate: %s"),
534 		    cmd_info.cert);
535 		ret = EXIT_BAD_CERT;
536 		goto cleanup;
537 	}
538 
539 	if (cmd_info.privpath != NULL) {
540 		if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
541 		    cmd_info.privpath)) {
542 			es_error(gettext("Unable to load private key: %s"),
543 			    cmd_info.privpath);
544 			ret = EXIT_BAD_PRIVATEKEY;
545 			goto cleanup;
546 		}
547 	} else {
548 		char *pin = getpin();
549 		if (pin == NULL) {
550 			es_error(gettext("Unable to get PIN"));
551 			ret = EXIT_BAD_PRIVATEKEY;
552 			goto cleanup;
553 		}
554 		if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
555 		    cmd_info.token_label, pin)) {
556 			es_error(gettext("Unable to access private key "
557 			    "in token %s"), cmd_info.token_label);
558 			ret = EXIT_BAD_PRIVATEKEY;
559 			goto cleanup;
560 		}
561 	}
562 
563 	/*
564 	 * Get the DN from the certificate.
565 	 */
566 	if ((dn = elfcertlib_getdn(cert)) == NULL) {
567 		es_error(gettext("Unable to find DN in certificate %s"),
568 		    cmd_info.cert);
569 		ret = EXIT_SIGN_FAILED;
570 		goto cleanup;
571 	}
572 	dn_len = strlen(dn);
573 	cryptodebug("DN = %s", dn);
574 
575 	elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET);
576 	if (elfstat != ELFSIGN_SUCCESS) {
577 		if (elfstat != ELFSIGN_NOTSIGNED) {
578 			es_error(gettext("Unable to retrieve existing "
579 			    "signature block in %s"), object);
580 			ret = EXIT_SIGN_FAILED;
581 			goto cleanup;
582 		}
583 		fssp = NULL;
584 		/*
585 		 * force creation and naming of signature section
586 		 * so the hash doesn't change
587 		 */
588 		if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
589 		    cmd_info.es_action) != ELFSIGN_SUCCESS) {
590 			es_error(gettext("Unable to insert "
591 			    "signature block into %s"), object);
592 			ret = EXIT_SIGN_FAILED;
593 			goto cleanup;
594 		}
595 	}
596 
597 	bzero(hash, sizeof (hash));
598 	if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
599 		es_error(gettext("Unable to calculate hash of ELF object %s"),
600 		    object);
601 		ret = EXIT_SIGN_FAILED;
602 		goto cleanup;
603 	}
604 
605 	bzero(sig, sizeof (sig));
606 	if (!elfcertlib_sign(cmd_info.ess, cert,
607 	    hash, hash_len, sig, &sig_len)) {
608 		es_error(gettext("Unable to sign %s using key from %s"),
609 		    object, cmd_info.privpath ?
610 		    cmd_info.privpath : cmd_info.token_label);
611 		ret = EXIT_SIGN_FAILED;
612 		goto cleanup;
613 	}
614 
615 	{ /* DEBUG START */
616 		const int sigstr_len = sizeof (char) * sig_len * 2 + 1;
617 		char *sigstr = malloc(sigstr_len);
618 
619 		tohexstr(sig, sig_len, sigstr, sigstr_len);
620 		cryptodebug("sig value is: %s", sigstr);
621 		free(sigstr);
622 	} /* DEBUG END */
623 
624 	fssp = elfsign_insert_dso(cmd_info.ess, fssp,
625 	    dn, dn_len, sig, sig_len, NULL, 0);
626 	if (fssp == NULL) {
627 		es_error(gettext("Unable to prepare signature for %s"),
628 		    object);
629 		ret = EXIT_SIGN_FAILED;
630 		goto cleanup;
631 	}
632 	if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
633 	    cmd_info.es_action) != ELFSIGN_SUCCESS) {
634 		es_error(gettext("Unable to update %s: with signature"),
635 		    object);
636 		ret = EXIT_SIGN_FAILED;
637 		goto cleanup;
638 	}
639 	if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) {
640 		(void) fprintf(stdout,
641 		    gettext("elfsign: %s signed successfully.\n"),
642 		    object);
643 	}
644 	if (cmd_info.verbose) {
645 		struct ELFsign_sig_info *esip;
646 
647 		if (elfsign_sig_info(fssp, &esip)) {
648 			sig_info_print(esip);
649 			elfsign_sig_info_free(esip);
650 		}
651 	}
652 
653 	ret = EXIT_OKAY;
654 
655 cleanup:
656 	free(fssp);
657 	bzero(sig, sig_len);
658 	bzero(hash, hash_len);
659 
660 	if (cert != NULL)
661 		elfcertlib_releasecert(cmd_info.ess, cert);
662 	if (cmd_info.ess != NULL)
663 		elfsign_end(cmd_info.ess);
664 
665 	return (ret);
666 }
667 
668 #define	ESA_ERROR(str, esa_file) {	\
669 	int realerrno = errno;		\
670 	es_error(gettext(str), esa_file, strerror(realerrno)); \
671 	goto clean_esa;			\
672 }
673 
674 /*
675  * Generate the elfsign activation file (.esa) for this request.
676  * The .esa file should contain the signature of main binary
677  * signed with an unlimited certificate, the DN and its own signature.
678  *
679  * The format is as follows:
680  *   -----------------------------
681  * A | main signature length     |
682  *   -----------------------------
683  * B | main signature (copy of   |
684  *   |   signature from original |
685  *   |   limited-use binary      |
686  *   -----------------------------
687  * C | signing DN length         |
688  *   -----------------------------
689  * D | signing DN                |
690  *   -----------------------------
691  * E | esa signature length      |
692  *   -----------------------------
693  * F | esa signature =           |
694  *   |   RSA(HASH(A||B)          |
695  *   -----------------------------
696  * (lengths are in the same endianness as the original object)
697  *
698  * cmd_info.ess set for the main binary is correct here, since this
699  * is the only elf object we are actually dealing with during the .esa
700  * generation.
701  */
702 static ret_t
703 do_gen_esa(char *object)
704 {
705 	ret_t	ret;
706 
707 	/* variables used for signing and writing to .esa file */
708 	char	*elfobj_esa;
709 	size_t	elfobj_esa_len;
710 	int	esa_fd;
711 	mode_t	mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
712 	uchar_t	*esa_buf = NULL;
713 	size_t	esa_buf_len = 0;
714 	uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
715 	size_t  hash_len = SIG_MAX_LENGTH;
716 	uchar_t	esa_sig[SIG_MAX_LENGTH];
717 	size_t	esa_sig_len = SIG_MAX_LENGTH;
718 	struct filesignatures *fssp = NULL;
719 	size_t fslen;
720 	ELFCert_t cert = NULL;
721 	char *dn;
722 	size_t dn_len;
723 	uchar_t tmp_buf[sizeof (uint32_t)];
724 	int realerrno = 0;
725 
726 	/*
727 	 * variables used for finding information on signer of main
728 	 * elfobject.
729 	 */
730 	uchar_t	orig_signature[SIG_MAX_LENGTH];
731 	size_t	orig_sig_len = sizeof (orig_signature);
732 
733 	cryptodebug("do_gen_esa");
734 	if ((ret = getelfobj(object)) != EXIT_OKAY)
735 		return (ret);
736 	ret = EXIT_SIGN_FAILED;
737 
738 	if (cmd_info.token_label &&
739 	    !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) {
740 		es_error(gettext("Unable to access token: %s"),
741 		    cmd_info.token_label);
742 		ret = EXIT_SIGN_FAILED;
743 		goto clean_esa;
744 	}
745 
746 	if ((ret = setcertpath()) != EXIT_OKAY)
747 		goto clean_esa;
748 
749 	/*
750 	 * Find the certificate we need to sign the activation file with.
751 	 */
752 	if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
753 	    cmd_info.es_action)) {
754 		es_error(gettext("Unable to load certificate: %s"),
755 		    cmd_info.cert);
756 		ret = EXIT_BAD_CERT;
757 		goto clean_esa;
758 	}
759 
760 	if (cmd_info.privpath != NULL) {
761 		if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
762 		    cmd_info.privpath)) {
763 			es_error(gettext("Unable to load private key: %s"),
764 			    cmd_info.privpath);
765 			ret = EXIT_BAD_PRIVATEKEY;
766 			goto clean_esa;
767 		}
768 	} else {
769 		char *pin = getpin();
770 
771 		if (pin == NULL) {
772 			cryptoerror(LOG_STDERR, gettext("Unable to get PIN"));
773 			ret = EXIT_BAD_PRIVATEKEY;
774 			goto clean_esa;
775 		}
776 		if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
777 		    cmd_info.token_label, pin)) {
778 			es_error(gettext("Unable to access private key "
779 			    "in token %s"), cmd_info.token_label);
780 			ret = EXIT_BAD_PRIVATEKEY;
781 			goto clean_esa;
782 		}
783 	}
784 
785 	/*
786 	 * Get the DN from the certificate.
787 	 */
788 	if ((dn = elfcertlib_getdn(cert)) == NULL) {
789 		es_error(gettext("Unable to find DN in certifiate %s"),
790 		    cmd_info.cert);
791 		goto clean_esa;
792 	}
793 	dn_len = strlen(dn);
794 	cryptodebug("DN = %s", dn);
795 
796 	/*
797 	 * Make sure they are not trying to sign .esa file with a
798 	 * limited certificate.
799 	 */
800 	if (strstr(dn, USAGELIMITED) != NULL) {
801 		es_error(gettext("Activation file must be signed with a "
802 		    "certficate without %s."), USAGELIMITED);
803 		goto clean_esa;
804 	}
805 
806 	/*
807 	 * Find information in the associated elfobject that will
808 	 * be needed to generate the activation file.
809 	 */
810 	if (elfsign_signatures(cmd_info.ess, &fssp, &fslen, ES_GET) !=
811 	    ELFSIGN_SUCCESS) {
812 		es_error(gettext("%s must be signed first, before an "
813 		    "associated activation file can be created."),
814 		    object);
815 		goto clean_esa;
816 	}
817 	if (elfsign_extract_sig(cmd_info.ess, fssp,
818 	    orig_signature, &orig_sig_len) == FILESIG_UNKNOWN) {
819 		es_error(gettext("elfsign can not create "
820 		    "an associated activation file for the "
821 		    "signature format of %s."),
822 		    object);
823 		goto clean_esa;
824 	}
825 	{ /* DEBUG START */
826 		const int sigstr_len = orig_sig_len * 2 + 1;
827 		char *sigstr = malloc(sigstr_len);
828 
829 		tohexstr(orig_signature, orig_sig_len, sigstr, sigstr_len);
830 		cryptodebug("signature value is: %s", sigstr);
831 		cryptodebug("sig size value is: %d", orig_sig_len);
832 		free(sigstr);
833 	} /* DEBUG END */
834 
835 	esa_buf_len = sizeof (uint32_t) + orig_sig_len;
836 	esa_buf = malloc(esa_buf_len);
837 	if (esa_buf == NULL) {
838 		es_error(gettext("Unable to allocate memory for .esa buffer"));
839 		goto clean_esa;
840 	}
841 
842 	/*
843 	 * Write eventual contents of .esa file to a temporary
844 	 * buffer, so we can sign it before writing out to
845 	 * the file.
846 	 */
847 	elfsign_buffer_len(cmd_info.ess, &orig_sig_len, esa_buf, ES_UPDATE);
848 	(void) memcpy(esa_buf + sizeof (uint32_t), orig_signature,
849 	    orig_sig_len);
850 
851 	if (elfsign_hash_esa(cmd_info.ess, esa_buf, esa_buf_len,
852 	    &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
853 		es_error(gettext("Unable to calculate activation hash"));
854 		goto clean_esa;
855 	}
856 
857 	/*
858 	 * sign the buffer for the .esa file
859 	 */
860 	if (!elfcertlib_sign(cmd_info.ess, cert,
861 	    hash_ptr, hash_len, esa_sig, &esa_sig_len)) {
862 		es_error(gettext("Unable to sign .esa data using key from %s"),
863 		    cmd_info.privpath ?
864 		    cmd_info.privpath : cmd_info.token_label);
865 		goto clean_esa;
866 	}
867 
868 	{ /* DEBUG START */
869 		const int sigstr_len = esa_sig_len * 2 + 1;
870 		char *sigstr = malloc(sigstr_len);
871 
872 		tohexstr(esa_sig, esa_sig_len, sigstr, sigstr_len);
873 		cryptodebug("esa signature value is: %s", sigstr);
874 		cryptodebug("esa size value is: %d", esa_sig_len);
875 		free(sigstr);
876 	} /* DEBUG END */
877 
878 	/*
879 	 * Create the empty activation file once we know
880 	 * we are working with the good data.
881 	 */
882 	elfobj_esa_len = strlen(object) + ESA_LEN + 1;
883 	elfobj_esa = malloc(elfobj_esa_len);
884 
885 	if (elfobj_esa == NULL) {
886 		es_error(gettext("Unable to allocate buffer for esa filename"));
887 		goto clean_esa;
888 	}
889 
890 	(void) strlcpy(elfobj_esa, object, elfobj_esa_len);
891 	(void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
892 
893 	cryptodebug("Creating .esa file: %s", elfobj_esa);
894 
895 	if ((esa_fd = open(elfobj_esa, O_WRONLY|O_CREAT|O_EXCL, mode)) == -1) {
896 		ESA_ERROR("Unable to create activation file: %s. %s.",
897 		    elfobj_esa);
898 	}
899 
900 	if (write(esa_fd, esa_buf, esa_buf_len) != esa_buf_len) {
901 		ESA_ERROR("Unable to write contents to %s. %s.",
902 		    elfobj_esa);
903 	}
904 
905 	{ /* DEBUG START */
906 		const int sigstr_len = dn_len * 2 + 1;
907 		char *sigstr = malloc(sigstr_len);
908 
909 		tohexstr((uchar_t *)dn, dn_len, sigstr, sigstr_len);
910 		cryptodebug("dn value is: %s", sigstr);
911 		cryptodebug("dn size value is: %d", dn_len);
912 		free(sigstr);
913 	} /* DEBUG END */
914 
915 	elfsign_buffer_len(cmd_info.ess, &dn_len, tmp_buf, ES_UPDATE);
916 	if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
917 		ESA_ERROR("Unable to write dn_len to %s. %s.", elfobj_esa);
918 	}
919 
920 	if (write(esa_fd, dn, dn_len) != dn_len) {
921 		ESA_ERROR("Unable to write dn to %s. %s.", elfobj_esa);
922 	}
923 
924 	elfsign_buffer_len(cmd_info.ess, &esa_sig_len, tmp_buf, ES_UPDATE);
925 	if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
926 		ESA_ERROR("Unable to write .esa signature len to %s. %s.",
927 		    elfobj_esa);
928 	}
929 
930 	if (write(esa_fd, esa_sig, esa_sig_len) != esa_sig_len) {
931 		realerrno = errno;
932 		es_error(gettext("Unable to write .esa signature. %s."),
933 		    strerror(realerrno));
934 		goto clean_esa;
935 	}
936 
937 	ret = EXIT_OKAY;
938 
939 clean_esa:
940 	free(fssp);
941 	if (esa_fd != -1)
942 		(void) close(esa_fd);
943 
944 	if (esa_buf != NULL)
945 		free(esa_buf);
946 
947 	bzero(esa_sig, esa_sig_len);
948 
949 	if (cert != NULL)
950 		elfcertlib_releasecert(cmd_info.ess, cert);
951 	if (cmd_info.ess != NULL)
952 		elfsign_end(cmd_info.ess);
953 
954 	return (ret);
955 }
956 
957 /*
958  * Verify the signature of the object
959  * This subcommand is intended to be used by developers during their build
960  * processes.  Therefore we can not assume that the certificate is in
961  * /etc/crypto/certs so we must use the path we got from the commandline.
962  */
963 static ret_t
964 do_verify(char *object)
965 {
966 	ELFsign_status_t res;
967 	struct ELFsign_sig_info	*esip;
968 	ret_t	retval;
969 
970 	cryptodebug("do_verify");
971 	if ((retval = getelfobj(object)) != EXIT_OKAY)
972 		return (retval);
973 
974 	if ((retval = setcertpath()) != EXIT_OKAY) {
975 		elfsign_end(cmd_info.ess);
976 		return (retval);
977 	}
978 
979 	res = elfsign_verify_signature(cmd_info.ess, &esip);
980 	switch (res) {
981 	case ELFSIGN_SUCCESS:
982 		(void) fprintf(stdout,
983 		    gettext("elfsign: verification of %s passed.\n"),
984 		    object);
985 		if (cmd_info.verbose)
986 			sig_info_print(esip);
987 		retval = EXIT_OKAY;
988 		break;
989 	case ELFSIGN_RESTRICTED:
990 		(void) fprintf(stdout,
991 		    gettext("elfsign: verification of %s passed, "
992 		    "but restricted.\n"), object);
993 		if (cmd_info.verbose)
994 			sig_info_print(esip);
995 		retval = EXIT_OKAY;
996 		break;
997 	case ELFSIGN_FAILED:
998 	case ELFSIGN_INVALID_CERTPATH:
999 		es_error(gettext("verification of %s failed."),
1000 		    object);
1001 		if (cmd_info.verbose)
1002 			sig_info_print(esip);
1003 		retval = EXIT_VERIFY_FAILED;
1004 		break;
1005 	case ELFSIGN_NOTSIGNED:
1006 		es_error(gettext("no signature found in %s."),
1007 		    object);
1008 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
1009 		break;
1010 	default:
1011 		es_error(gettext("unexpected failure attempting verification "
1012 		    "of %s."), object);
1013 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
1014 		break;
1015 	}
1016 
1017 	if (esip != NULL)
1018 		elfsign_sig_info_free(esip);
1019 	if (cmd_info.ess != NULL)
1020 		elfsign_end(cmd_info.ess);
1021 	return (retval);
1022 }
1023 
1024 #define	SET_VALUE(f, s) \
1025 	kmfrv = f; \
1026 	if (kmfrv != KMF_OK) { \
1027 		char *e = NULL; \
1028 		(void) kmf_get_kmf_error_str(kmfrv, &e); \
1029 		cryptoerror(LOG_STDERR, \
1030 			gettext("Failed to %s: %s\n"), \
1031 			s, (e ? e : "unknown error")); \
1032 		if (e) free(e); \
1033 		goto cleanup; \
1034 	}
1035 
1036 static KMF_RETURN
1037 create_csr(char *dn)
1038 {
1039 	KMF_RETURN kmfrv = KMF_OK;
1040 	KMF_HANDLE_T kmfhandle = NULL;
1041 	KMF_KEY_HANDLE pubk, prik;
1042 	KMF_X509_NAME csrSubject;
1043 	KMF_CSR_DATA csr;
1044 	KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
1045 	KMF_DATA signedCsr = { NULL, 0 };
1046 	char *err;
1047 	KMF_ATTRIBUTE	attrlist[16];
1048 	KMF_ENCODE_FORMAT	format;
1049 	KMF_KEYSTORE_TYPE	kstype;
1050 	KMF_KEY_ALG	keytype;
1051 	uint32_t	keylength;
1052 	KMF_CREDENTIAL	cred;
1053 	char	*pin = NULL;
1054 	int	numattr;
1055 
1056 	if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
1057 		(void) kmf_get_kmf_error_str(kmfrv, &err);
1058 		cryptoerror(LOG_STDERR,
1059 		    gettext("Error initializing KMF: %s\n"),
1060 		    (err ? err : "unknown error"));
1061 		if (err)
1062 			free(err);
1063 		return (kmfrv);
1064 	}
1065 	(void) memset(&csr, 0, sizeof (csr));
1066 	(void) memset(&csrSubject, 0, sizeof (csrSubject));
1067 
1068 	if (cmd_info.privpath != NULL) {
1069 		kstype = KMF_KEYSTORE_OPENSSL;
1070 		format = KMF_FORMAT_ASN1;
1071 	} else {
1072 		boolean_t	readonly;
1073 		/* args checking verified (cmd_info.token_label != NULL) */
1074 
1075 		/* Get a PIN to store the private key in the token */
1076 		pin = getpin();
1077 
1078 		if (pin == NULL) {
1079 			(void) kmf_finalize(kmfhandle);
1080 			return (KMF_ERR_AUTH_FAILED);
1081 		}
1082 
1083 		kstype = KMF_KEYSTORE_PK11TOKEN;
1084 		readonly = B_FALSE;
1085 
1086 		numattr = 0;
1087 		kmf_set_attr_at_index(attrlist, numattr++,
1088 		    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
1089 		kmf_set_attr_at_index(attrlist, numattr++,
1090 		    KMF_TOKEN_LABEL_ATTR, cmd_info.token_label,
1091 		    strlen(cmd_info.token_label));
1092 		kmf_set_attr_at_index(attrlist, numattr++,
1093 		    KMF_READONLY_ATTR, &readonly, sizeof (readonly));
1094 		kmfrv = kmf_configure_keystore(kmfhandle, numattr, attrlist);
1095 		if (kmfrv != KMF_OK) {
1096 			goto cleanup;
1097 		}
1098 	}
1099 
1100 	/* Create the RSA keypair */
1101 	keytype = KMF_RSA;
1102 	keylength = ES_DEFAULT_KEYSIZE;
1103 	(void) memset(&prik, 0, sizeof (prik));
1104 	(void) memset(&pubk, 0, sizeof (pubk));
1105 
1106 	numattr = 0;
1107 	kmf_set_attr_at_index(attrlist, numattr++,
1108 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
1109 	kmf_set_attr_at_index(attrlist, numattr++,
1110 	    KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
1111 	kmf_set_attr_at_index(attrlist, numattr++,
1112 	    KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
1113 	if (pin != NULL) {
1114 		cred.cred = pin;
1115 		cred.credlen = strlen(pin);
1116 		kmf_set_attr_at_index(attrlist, numattr++,
1117 		    KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL));
1118 	}
1119 	kmf_set_attr_at_index(attrlist, numattr++,
1120 	    KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE));
1121 	kmf_set_attr_at_index(attrlist, numattr++,
1122 	    KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE));
1123 	if (kstype == KMF_KEYSTORE_OPENSSL) {
1124 		kmf_set_attr_at_index(attrlist, numattr++,
1125 		    KMF_KEY_FILENAME_ATTR, cmd_info.privpath,
1126 		    strlen(cmd_info.privpath));
1127 		kmf_set_attr_at_index(attrlist, numattr++,
1128 		    KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format));
1129 	}
1130 
1131 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
1132 	if (kmfrv != KMF_OK) {
1133 		(void) kmf_get_kmf_error_str(kmfrv, &err);
1134 		cryptoerror(LOG_STDERR,
1135 		    gettext("Create RSA keypair failed: %s"),
1136 		    (err ? err : "unknown error"));
1137 		free(err);
1138 		goto cleanup;
1139 	}
1140 
1141 	kmfrv = kmf_dn_parser(dn, &csrSubject);
1142 	if (kmfrv != KMF_OK) {
1143 		(void) kmf_get_kmf_error_str(kmfrv, &err);
1144 		cryptoerror(LOG_STDERR,
1145 		    gettext("Error parsing subject name: %s\n"),
1146 		    (err ? err : "unknown error"));
1147 		free(err);
1148 		goto cleanup;
1149 	}
1150 
1151 	SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair");
1152 
1153 	SET_VALUE(kmf_set_csr_version(&csr, 2), "version number");
1154 
1155 	SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name");
1156 
1157 	SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm");
1158 
1159 	if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) ==
1160 	    KMF_OK) {
1161 		kmfrv = kmf_create_csr_file(&signedCsr, KMF_FORMAT_PEM,
1162 		    cmd_info.cert);
1163 	}
1164 
1165 cleanup:
1166 	(void) kmf_free_kmf_key(kmfhandle, &prik);
1167 	(void) kmf_free_data(&signedCsr);
1168 	(void) kmf_free_signed_csr(&csr);
1169 	(void) kmf_finalize(kmfhandle);
1170 
1171 	return (kmfrv);
1172 }
1173 
1174 static boolean_t
1175 is_restricted(void)
1176 {
1177 	char	nr[80]; /* Non-retail provider? big buffer for l10n */
1178 	char	*yeschar = nl_langinfo(YESSTR);
1179 	char	*nochar = nl_langinfo(NOSTR);
1180 
1181 	/*
1182 	 * Find out if user will need an activation file.
1183 	 * These questions cover cases #1 and #2 from the Jumbo Export
1184 	 * Control case.  The logic of these questions should not be modified
1185 	 * without consulting the jumbo case, unless there is a new
1186 	 * export case or a change in export/import regulations for Sun
1187 	 * and Sun customers.
1188 	 * Case #3 should be covered in the developer documentation.
1189 	 */
1190 /* BEGIN CSTYLED */
1191 	(void) fprintf(stdout, gettext("\n"
1192 "The government of the United States of America restricts the export of \n"
1193 "\"open cryptographic interfaces\", also known as \"crypto-with-a-hole\".\n"
1194 "Due to this restriction, all providers for the Solaris cryptographic\n"
1195 "framework must be signed, regardless of the country of origin.\n\n"));
1196 
1197 	(void) fprintf(stdout, gettext(
1198 "The terms \"retail\" and \"non-retail\" refer to export classifications \n"
1199 "for products manufactured in the USA.  These terms define the portion of the\n"
1200 "world where the product may be shipped.  Roughly speaking, \"retail\" is \n"
1201 "worldwide (minus certain excluded nations) and \"non-retail\" is domestic \n"
1202 "only (plus some highly favored nations).  If your provider is subject to\n"
1203 "USA export control, then you must obtain an export approval (classification)\n"
1204 "from the government of the USA before exporting your provider.  It is\n"
1205 "critical that you specify the obtained (or expected, when used during \n"
1206 "development) classification to the following questions so that your provider\n"
1207 "will be appropriately signed.\n\n"));
1208 
1209 	for (;;) {
1210 		(void) fprintf(stdout, gettext(
1211 "Do you have retail export approval for use without restrictions based \n"
1212 "on the caller (for example, IPsec)? [Yes/No] "));
1213 /* END CSTYLED */
1214 
1215 		(void) fflush(stdout);
1216 
1217 		(void) fgets(nr, sizeof (nr), stdin);
1218 		if (nr == NULL)
1219 			goto demand_answer;
1220 
1221 		nr[strlen(nr) - 1] = '\0';
1222 
1223 		if (strncasecmp(nochar, nr, 1) == 0) {
1224 /* BEGIN CSTYLED */
1225 			(void) fprintf(stdout, gettext("\n"
1226 "If you have non-retail export approval for unrestricted use of your provider\n"
1227 "by callers, are you also planning to receive retail approval by restricting \n"
1228 "which export sensitive callers (for example, IPsec) may use your \n"
1229 "provider? [Yes/No] "));
1230 /* END CSTYLED */
1231 
1232 			(void) fflush(stdout);
1233 
1234 			(void) fgets(nr, sizeof (nr), stdin);
1235 
1236 			/*
1237 			 * flush standard input so any remaining text
1238 			 * does not affect next read.
1239 			 */
1240 			(void) fflush(stdin);
1241 
1242 			if (nr == NULL)
1243 				goto demand_answer;
1244 
1245 			nr[strlen(nr) - 1] = '\0';
1246 
1247 			if (strncasecmp(nochar, nr, 1) == 0) {
1248 				return (B_FALSE);
1249 			} else if (strncasecmp(yeschar, nr, 1) == 0) {
1250 				return (B_TRUE);
1251 			} else
1252 				goto demand_answer;
1253 
1254 		} else if (strncasecmp(yeschar, nr, 1) == 0) {
1255 			return (B_FALSE);
1256 		}
1257 
1258 	demand_answer:
1259 		(void) fprintf(stdout,
1260 		    gettext("You must specify an answer.\n\n"));
1261 	}
1262 }
1263 
1264 #define	CN_MAX_LENGTH	64	/* Verisign implementation limit */
1265 /*
1266  * Generate a certificate request into the file named cmd_info.cert
1267  */
1268 /*ARGSUSED*/
1269 static ret_t
1270 do_cert_request(char *object)
1271 {
1272 	const char	 PartnerDNFMT[] =
1273 	    "CN=%s, "
1274 	    "OU=Class B, "
1275 	    "%sOU=Solaris Cryptographic Framework, "
1276 	    "OU=Partner Object Signing, "
1277 	    "O=Sun Microsystems Inc";
1278 	const char	 SunCDNFMT[] =
1279 	    "CN=%s, "
1280 	    "OU=Class B, "
1281 	    "%sOU=Solaris Cryptographic Framework, "
1282 	    "OU=Corporate Object Signing, "
1283 	    "O=Sun Microsystems Inc";
1284 	const char	 SunSDNFMT[] =
1285 	    "CN=%s, "
1286 	    "OU=Class B, "
1287 	    "%sOU=Solaris Signed Execution, "
1288 	    "OU=Corporate Object Signing, "
1289 	    "O=Sun Microsystems Inc";
1290 	const char	 *dnfmt = NULL;
1291 	char	cn[CN_MAX_LENGTH + 1];
1292 	char	*dn = NULL;
1293 	size_t	dn_len;
1294 	char	*restriction = "";
1295 	KMF_RETURN   kmfret;
1296 	cryptodebug("do_cert_request");
1297 
1298 	/*
1299 	 * Get the DN prefix from the user
1300 	 */
1301 	switch (cmd_info.internal_req) {
1302 	case 'c':
1303 		dnfmt = SunCDNFMT;
1304 		(void) fprintf(stdout, gettext(
1305 		    "Enter Sun Microsystems, Inc. Release name.\n"
1306 		    "This will be the prefix of the Certificate DN: "));
1307 		break;
1308 	case 's':
1309 		dnfmt = SunSDNFMT;
1310 		(void) fprintf(stdout, gettext(
1311 		    "Enter Sun Microsystems, Inc. Release name.\n"
1312 		    "This will be the prefix of the Certificate DN: "));
1313 		break;
1314 	default:
1315 		dnfmt = PartnerDNFMT;
1316 		(void) fprintf(stdout, gettext(
1317 		    "Enter Company Name / Stock Symbol"
1318 		    " or some other globally unique identifier.\n"
1319 		    "This will be the prefix of the Certificate DN: "));
1320 		break;
1321 	}
1322 
1323 	(void) fgets(cn, sizeof (cn), stdin);
1324 	if ((cn == NULL) || (cn[0] == '\n')) {
1325 		es_error(gettext("you must specify a Certificate DN prefix"));
1326 		return (EXIT_INVALID_ARG);
1327 	}
1328 
1329 	if (cn[strlen(cn) - 1] == '\n') {
1330 		cn[strlen(cn) - 1] = '\0';	/* chop trailing \n */
1331 	} else {
1332 		es_error(gettext("You must specify a Certificate DN prefix "
1333 		    "of no more than %d characters"), CN_MAX_LENGTH);
1334 		return (EXIT_INVALID_ARG);
1335 	}
1336 
1337 	/*
1338 	 * determine if there is an export restriction
1339 	 */
1340 	switch (cmd_info.internal_req) {
1341 	case 's':
1342 		restriction = "";
1343 		break;
1344 	default:
1345 		restriction = is_restricted() ? USAGELIMITED ", " : "";
1346 		break;
1347 	}
1348 
1349 	/* Update DN string */
1350 	dn_len = strlen(cn) + strlen(dnfmt) + strlen(restriction);
1351 	dn = malloc(dn_len + 1);
1352 	(void) snprintf(dn, dn_len, dnfmt, cn, restriction);
1353 
1354 	cryptodebug("Generating Certificate request for DN: %s", dn);
1355 	kmfret = create_csr(dn);
1356 	free(dn);
1357 	if (kmfret == KMF_OK)
1358 		return (EXIT_OKAY);
1359 	else
1360 		return (EXIT_CSR_FAILED);
1361 }
1362 
1363 static void
1364 str_print(char *s)
1365 {
1366 	if (s == NULL)
1367 		return;
1368 	(void) fprintf(stdout, "%s\n", s);
1369 }
1370 
1371 /*ARGSUSED*/
1372 static ret_t
1373 do_list(char *object)
1374 {
1375 	ret_t	retval;
1376 
1377 	if (cmd_info.elfcnt > 0) {
1378 		ELFsign_status_t	elfstat;
1379 		struct filesignatures	*fssp = NULL;
1380 		size_t fs_len;
1381 		struct ELFsign_sig_info	*esip;
1382 
1383 		if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
1384 			return (retval);
1385 		elfstat = elfsign_signatures(cmd_info.ess,
1386 		    &fssp, &fs_len, ES_GET);
1387 		if (elfstat == ELFSIGN_SUCCESS) {
1388 			retval = EXIT_OKAY;
1389 			if (elfsign_sig_info(fssp, &esip)) {
1390 				switch (cmd_info.field) {
1391 				case FLD_FORMAT:
1392 					str_print(esip->esi_format);
1393 					break;
1394 				case FLD_SIGNER:
1395 					str_print(esip->esi_signer);
1396 					break;
1397 				case FLD_TIME:
1398 					if (esip->esi_time == 0)
1399 						retval = EXIT_INVALID_ARG;
1400 					else
1401 						str_print(time_str(
1402 						    esip->esi_time));
1403 					break;
1404 				default:
1405 					retval = EXIT_INVALID_ARG;
1406 				}
1407 				elfsign_sig_info_free(esip);
1408 			}
1409 			free(fssp);
1410 		} else
1411 			retval = EXIT_VERIFY_FAILED_UNSIGNED;
1412 		elfsign_end(cmd_info.ess);
1413 	} else {
1414 		ELFCert_t	cert;
1415 		/*
1416 		 * Initialize the ESS record here even though we are not
1417 		 * actually opening any ELF files.
1418 		 */
1419 		if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
1420 		    ELFSIGN_SUCCESS)
1421 			return (EXIT_MEMORY_ERROR);
1422 
1423 		if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
1424 		    &cert, cmd_info.es_action)) {
1425 			retval = EXIT_OKAY;
1426 			switch (cmd_info.field) {
1427 			case FLD_SUBJECT:
1428 				str_print(elfcertlib_getdn(cert));
1429 				break;
1430 			case FLD_ISSUER:
1431 				str_print(elfcertlib_getissuer(cert));
1432 				break;
1433 			default:
1434 				retval = EXIT_INVALID_ARG;
1435 			}
1436 			elfcertlib_releasecert(cmd_info.ess, cert);
1437 		} else
1438 			retval = EXIT_BAD_CERT;
1439 		elfsign_end(cmd_info.ess);
1440 	}
1441 
1442 	return (retval);
1443 }
1444 
1445 static void
1446 es_error(const char *fmt, ...)
1447 {
1448 	char msgbuf[BUFSIZ];
1449 	va_list	args;
1450 
1451 	va_start(args, fmt);
1452 	(void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
1453 	va_end(args);
1454 	(void) fflush(stdout);
1455 	cryptoerror(LOG_STDERR, "%s", msgbuf);
1456 	(void) fflush(stderr);
1457 }
1458 
1459 static char *
1460 time_str(time_t t)
1461 {
1462 	static char	buf[80];
1463 	char		*bufp;
1464 
1465 	bufp = buf;
1466 	if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
1467 		bufp = ctime(&t);
1468 	return (bufp);
1469 }
1470 
1471 static void
1472 sig_info_print(struct ELFsign_sig_info *esip)
1473 {
1474 	if (esip == NULL)
1475 		return;
1476 	(void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
1477 	(void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
1478 	if (esip->esi_time == 0)
1479 		return;
1480 	(void) fprintf(stdout, gettext("signed on: %s.\n"),
1481 	    time_str(esip->esi_time));
1482 }
1483