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