xref: /illumos-gate/usr/src/cmd/cmd-crypto/elfsign/elfsign.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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 2007 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;
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;
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: %d"), 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 		elfsign_end(cmd_info.ess);
525 		es_error(gettext("Unable to access token: %s"),
526 		    cmd_info.token_label);
527 		ret = EXIT_SIGN_FAILED;
528 		goto cleanup;
529 	}
530 
531 	if ((ret = setcertpath()) != EXIT_OKAY)
532 		goto cleanup;
533 
534 	if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
535 	    cmd_info.es_action)) {
536 		es_error(gettext("Unable to load certificate: %s"),
537 		    cmd_info.cert);
538 		ret = EXIT_BAD_CERT;
539 		goto cleanup;
540 	}
541 
542 	if (cmd_info.privpath != NULL) {
543 		if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
544 		    cmd_info.privpath)) {
545 			es_error(gettext("Unable to load private key: %s"),
546 			    cmd_info.privpath);
547 			ret = EXIT_BAD_PRIVATEKEY;
548 			goto cleanup;
549 		}
550 	} else {
551 		char *pin = getpin();
552 		if (pin == NULL) {
553 			es_error(gettext("Unable to get PIN"));
554 			ret = EXIT_BAD_PRIVATEKEY;
555 			goto cleanup;
556 		}
557 		if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
558 		    cmd_info.token_label, pin)) {
559 			es_error(gettext("Unable to access private key "
560 			    "in token %s"), cmd_info.token_label);
561 			ret = EXIT_BAD_PRIVATEKEY;
562 			goto cleanup;
563 		}
564 	}
565 
566 	/*
567 	 * Get the DN from the certificate.
568 	 */
569 	if ((dn = elfcertlib_getdn(cert)) == NULL) {
570 		es_error(gettext("Unable to find DN in certificate %s"),
571 		    cmd_info.cert);
572 		ret = EXIT_SIGN_FAILED;
573 		goto cleanup;
574 	}
575 	dn_len = strlen(dn);
576 	cryptodebug("DN = %s", dn);
577 
578 	elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET);
579 	if (elfstat != ELFSIGN_SUCCESS) {
580 		if (elfstat != ELFSIGN_NOTSIGNED) {
581 			es_error(gettext("Unable to retrieve existing "
582 			    "signature block in %s"), object);
583 			ret = EXIT_SIGN_FAILED;
584 			goto cleanup;
585 		}
586 		fssp = NULL;
587 		/*
588 		 * force creation and naming of signature section
589 		 * so the hash doesn't change
590 		 */
591 		if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
592 		    cmd_info.es_action) != ELFSIGN_SUCCESS) {
593 			es_error(gettext("Unable to insert "
594 			    "signature block into %s"), object);
595 			ret = EXIT_SIGN_FAILED;
596 			goto cleanup;
597 		}
598 	}
599 
600 	bzero(hash, sizeof (hash));
601 	if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
602 		es_error(gettext("Unable to calculate hash of ELF object %s"),
603 		    object);
604 		ret = EXIT_SIGN_FAILED;
605 		goto cleanup;
606 	}
607 
608 	bzero(sig, sizeof (sig));
609 	if (!elfcertlib_sign(cmd_info.ess, cert,
610 	    hash, hash_len, sig, &sig_len)) {
611 		es_error(gettext("Unable to sign %s using key from %s"),
612 		    object, cmd_info.privpath ?
613 		    cmd_info.privpath : cmd_info.token_label);
614 		ret = EXIT_SIGN_FAILED;
615 		goto cleanup;
616 	}
617 
618 	{ /* DEBUG START */
619 		const int sigstr_len = sizeof (char) * sig_len * 2 + 1;
620 		char *sigstr = malloc(sigstr_len);
621 
622 		tohexstr(sig, sig_len, sigstr, sigstr_len);
623 		cryptodebug("sig value is: %s", sigstr);
624 		free(sigstr);
625 	} /* DEBUG END */
626 
627 	fssp = elfsign_insert_dso(cmd_info.ess, fssp,
628 	    dn, dn_len, sig, sig_len, NULL, 0);
629 	if (fssp == NULL) {
630 		es_error(gettext("Unable to prepare signature for %s"),
631 		    object);
632 		ret = EXIT_SIGN_FAILED;
633 		goto cleanup;
634 	}
635 	if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
636 	    cmd_info.es_action) != ELFSIGN_SUCCESS) {
637 		es_error(gettext("Unable to update %s: with signature"),
638 		    object);
639 		ret = EXIT_SIGN_FAILED;
640 		goto cleanup;
641 	}
642 	if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) {
643 		(void) fprintf(stdout,
644 		    gettext("elfsign: %s signed successfully.\n"),
645 		    object);
646 	}
647 	if (cmd_info.verbose) {
648 		struct ELFsign_sig_info *esip;
649 
650 		if (elfsign_sig_info(fssp, &esip)) {
651 			sig_info_print(esip);
652 			elfsign_sig_info_free(esip);
653 		}
654 	}
655 
656 	ret = EXIT_OKAY;
657 
658 cleanup:
659 	free(fssp);
660 	bzero(sig, sig_len);
661 	bzero(hash, hash_len);
662 
663 	if (cert != NULL)
664 		elfcertlib_releasecert(cmd_info.ess, cert);
665 	if (cmd_info.ess != NULL)
666 		elfsign_end(cmd_info.ess);
667 
668 	return (ret);
669 }
670 
671 #define	ESA_ERROR(str, esa_file) {	\
672 	int realerrno = errno;		\
673 	es_error(gettext(str), esa_file, strerror(realerrno)); \
674 	goto clean_esa;			\
675 }
676 
677 /*
678  * Generate the elfsign activation file (.esa) for this request.
679  * The .esa file should contain the signature of main binary
680  * signed with an unlimited certificate, the DN and its own signature.
681  *
682  * The format is as follows:
683  *   -----------------------------
684  * A | main signature length     |
685  *   -----------------------------
686  * B | main signature (copy of   |
687  *   |   signature from original |
688  *   |   limited-use binary      |
689  *   -----------------------------
690  * C | signing DN length         |
691  *   -----------------------------
692  * D | signing DN                |
693  *   -----------------------------
694  * E | esa signature length      |
695  *   -----------------------------
696  * F | esa signature =           |
697  *   |   RSA(HASH(A||B)          |
698  *   -----------------------------
699  * (lengths are in the same endianness as the original object)
700  *
701  * cmd_info.ess set for the main binary is correct here, since this
702  * is the only elf object we are actually dealing with during the .esa
703  * generation.
704  */
705 static ret_t
706 do_gen_esa(char *object)
707 {
708 	ret_t	ret;
709 
710 	/* variables used for signing and writing to .esa file */
711 	char	*elfobj_esa;
712 	size_t	elfobj_esa_len;
713 	int	esa_fd;
714 	mode_t	mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
715 	uchar_t	*esa_buf = NULL;
716 	size_t	esa_buf_len = 0;
717 	uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
718 	size_t  hash_len = SIG_MAX_LENGTH;
719 	uchar_t	esa_sig[SIG_MAX_LENGTH];
720 	size_t	esa_sig_len = SIG_MAX_LENGTH;
721 	struct filesignatures *fssp = NULL;
722 	size_t fslen;
723 	ELFCert_t cert = NULL;
724 	char *dn;
725 	size_t dn_len;
726 	uchar_t tmp_buf[sizeof (uint32_t)];
727 	int realerrno = 0;
728 
729 	/*
730 	 * variables used for finding information on signer of main
731 	 * elfobject.
732 	 */
733 	uchar_t	orig_signature[SIG_MAX_LENGTH];
734 	size_t	orig_sig_len = sizeof (orig_signature);
735 
736 	cryptodebug("do_gen_esa");
737 	if ((ret = getelfobj(object)) != EXIT_OKAY)
738 		return (ret);
739 	ret = EXIT_SIGN_FAILED;
740 
741 	/*
742 	 * Find the certificate we need to sign the activation file with.
743 	 */
744 	if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
745 	    cmd_info.es_action)) {
746 		es_error(gettext("Unable to load certificate: %s"),
747 		    cmd_info.cert);
748 		ret = EXIT_BAD_CERT;
749 		goto clean_esa;
750 	}
751 
752 	if (cmd_info.privpath != NULL) {
753 		if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
754 		    cmd_info.privpath)) {
755 			es_error(gettext("Unable to load private key: %s"),
756 			    cmd_info.privpath);
757 			ret = EXIT_BAD_PRIVATEKEY;
758 			goto clean_esa;
759 		}
760 	} else {
761 		char *pin = getpin();
762 
763 		if (pin == NULL) {
764 			cryptoerror(LOG_STDERR, gettext("Unable to get PIN"));
765 			ret = EXIT_BAD_PRIVATEKEY;
766 			goto clean_esa;
767 		}
768 		if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
769 		    cmd_info.token_label, pin)) {
770 			es_error(gettext("Unable to access private key "
771 			    "in token %s"), cmd_info.token_label);
772 			ret = EXIT_BAD_PRIVATEKEY;
773 			goto clean_esa;
774 		}
775 	}
776 
777 	/*
778 	 * Get the DN from the certificate.
779 	 */
780 	if ((dn = elfcertlib_getdn(cert)) == NULL) {
781 		es_error(gettext("Unable to find DN in certifiate %s"),
782 		    cmd_info.cert);
783 		goto clean_esa;
784 	}
785 	dn_len = strlen(dn);
786 	cryptodebug("DN = %s", dn);
787 
788 	/*
789 	 * Make sure they are not trying to sign .esa file with a
790 	 * limited certificate.
791 	 */
792 	if (strstr(dn, USAGELIMITED) != NULL) {
793 		es_error(gettext("Activation file must be signed with a "
794 		    "certficate without %s."), USAGELIMITED);
795 		goto clean_esa;
796 	}
797 
798 	/*
799 	 * Find information in the associated elfobject that will
800 	 * be needed to generate the activation file.
801 	 */
802 	if (elfsign_signatures(cmd_info.ess, &fssp, &fslen, ES_GET) !=
803 	    ELFSIGN_SUCCESS) {
804 		es_error(gettext("%s must be signed first, before an "
805 		    "associated activation file can be created."),
806 		    object);
807 		goto clean_esa;
808 	}
809 	if (elfsign_extract_sig(cmd_info.ess, fssp,
810 	    orig_signature, &orig_sig_len) == FILESIG_UNKNOWN) {
811 		es_error(gettext("elfsign can not create "
812 		    "an associated activation file for the "
813 		    "signature format of %s."),
814 		    object);
815 		goto clean_esa;
816 	}
817 	{ /* DEBUG START */
818 		const int sigstr_len = orig_sig_len * 2 + 1;
819 		char *sigstr = malloc(sigstr_len);
820 
821 		tohexstr(orig_signature, orig_sig_len, sigstr, sigstr_len);
822 		cryptodebug("signature value is: %s", sigstr);
823 		cryptodebug("sig size value is: %d", orig_sig_len);
824 		free(sigstr);
825 	} /* DEBUG END */
826 
827 	esa_buf_len = sizeof (uint32_t) + orig_sig_len;
828 	esa_buf = malloc(esa_buf_len);
829 	if (esa_buf == NULL) {
830 		es_error(gettext("Unable to allocate memory for .esa buffer"));
831 		goto clean_esa;
832 	}
833 
834 	/*
835 	 * Write eventual contents of .esa file to a temporary
836 	 * buffer, so we can sign it before writing out to
837 	 * the file.
838 	 */
839 	elfsign_buffer_len(cmd_info.ess, &orig_sig_len, esa_buf, ES_UPDATE);
840 	(void) memcpy(esa_buf + sizeof (uint32_t), orig_signature,
841 	    orig_sig_len);
842 
843 	if (elfsign_hash_esa(cmd_info.ess, esa_buf, esa_buf_len,
844 	    &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
845 		es_error(gettext("Unable to calculate activation hash"));
846 		goto clean_esa;
847 	}
848 
849 	/*
850 	 * sign the buffer for the .esa file
851 	 */
852 	if (!elfcertlib_sign(cmd_info.ess, cert,
853 	    hash_ptr, hash_len, esa_sig, &esa_sig_len)) {
854 		es_error(gettext("Unable to sign .esa data using key from %s"),
855 		    cmd_info.privpath ?
856 		    cmd_info.privpath : cmd_info.token_label);
857 		goto clean_esa;
858 	}
859 
860 	{ /* DEBUG START */
861 		const int sigstr_len = esa_sig_len * 2 + 1;
862 		char *sigstr = malloc(sigstr_len);
863 
864 		tohexstr(esa_sig, esa_sig_len, sigstr, sigstr_len);
865 		cryptodebug("esa signature value is: %s", sigstr);
866 		cryptodebug("esa size value is: %d", esa_sig_len);
867 		free(sigstr);
868 	} /* DEBUG END */
869 
870 	/*
871 	 * Create the empty activation file once we know
872 	 * we are working with the good data.
873 	 */
874 	elfobj_esa_len = strlen(object) + ESA_LEN + 1;
875 	elfobj_esa = malloc(elfobj_esa_len);
876 
877 	if (elfobj_esa == NULL) {
878 		es_error(gettext("Unable to allocate buffer for esa filename"));
879 		goto clean_esa;
880 	}
881 
882 	(void) strlcpy(elfobj_esa, object, elfobj_esa_len);
883 	(void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
884 
885 	cryptodebug("Creating .esa file: %s", elfobj_esa);
886 
887 	if ((esa_fd = open(elfobj_esa, O_WRONLY|O_CREAT|O_EXCL, mode)) == -1) {
888 		ESA_ERROR("Unable to create activation file: %s. %s.",
889 		    elfobj_esa);
890 	}
891 
892 	if (write(esa_fd, esa_buf, esa_buf_len) != esa_buf_len) {
893 		ESA_ERROR("Unable to write contents to %s. %s.",
894 		    elfobj_esa);
895 	}
896 
897 	{ /* DEBUG START */
898 		const int sigstr_len = dn_len * 2 + 1;
899 		char *sigstr = malloc(sigstr_len);
900 
901 		tohexstr((uchar_t *)dn, dn_len, sigstr, sigstr_len);
902 		cryptodebug("dn value is: %s", sigstr);
903 		cryptodebug("dn size value is: %d", dn_len);
904 		free(sigstr);
905 	} /* DEBUG END */
906 
907 	elfsign_buffer_len(cmd_info.ess, &dn_len, tmp_buf, ES_UPDATE);
908 	if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
909 		ESA_ERROR("Unable to write dn_len to %s. %s.", elfobj_esa);
910 	}
911 
912 	if (write(esa_fd, dn, dn_len) != dn_len) {
913 		ESA_ERROR("Unable to write dn to %s. %s.", elfobj_esa);
914 	}
915 
916 	elfsign_buffer_len(cmd_info.ess, &esa_sig_len, tmp_buf, ES_UPDATE);
917 	if (write(esa_fd, tmp_buf, sizeof (tmp_buf)) != sizeof (tmp_buf)) {
918 		ESA_ERROR("Unable to write .esa signature len to %s. %s.",
919 		    elfobj_esa);
920 	}
921 
922 	if (write(esa_fd, esa_sig, esa_sig_len) != esa_sig_len) {
923 		realerrno = errno;
924 		es_error(gettext("Unable to write .esa signature. %s."),
925 		    strerror(realerrno));
926 		goto clean_esa;
927 	}
928 
929 	ret = EXIT_OKAY;
930 
931 clean_esa:
932 	free(fssp);
933 	if (esa_fd != -1)
934 		(void) close(esa_fd);
935 
936 	if (esa_buf != NULL)
937 		free(esa_buf);
938 
939 	bzero(esa_sig, esa_sig_len);
940 
941 	if (cert != NULL)
942 		elfcertlib_releasecert(cmd_info.ess, cert);
943 	if (cmd_info.ess != NULL)
944 		elfsign_end(cmd_info.ess);
945 
946 	return (ret);
947 }
948 
949 /*
950  * Verify the signature of the object
951  * This subcommand is intended to be used by developers during their build
952  * processes.  Therefore we can not assume that the certificate is in
953  * /etc/crypto/certs so we must use the path we got from the commandline.
954  */
955 static ret_t
956 do_verify(char *object)
957 {
958 	ELFsign_status_t res;
959 	struct ELFsign_sig_info	*esip;
960 	ret_t	retval;
961 
962 	cryptodebug("do_verify");
963 	if ((retval = getelfobj(object)) != EXIT_OKAY)
964 		return (retval);
965 
966 	if ((retval = setcertpath()) != EXIT_OKAY) {
967 		elfsign_end(cmd_info.ess);
968 		return (retval);
969 	}
970 
971 	res = elfsign_verify_signature(cmd_info.ess, &esip);
972 	switch (res) {
973 	case ELFSIGN_SUCCESS:
974 		(void) fprintf(stdout,
975 		    gettext("elfsign: verification of %s passed.\n"),
976 		    object);
977 		if (cmd_info.verbose)
978 			sig_info_print(esip);
979 		retval = EXIT_OKAY;
980 		break;
981 	case ELFSIGN_RESTRICTED:
982 		(void) fprintf(stdout,
983 		    gettext("elfsign: verification of %s passed, "
984 		    "but restricted.\n"), object);
985 		if (cmd_info.verbose)
986 			sig_info_print(esip);
987 		retval = EXIT_OKAY;
988 		break;
989 	case ELFSIGN_FAILED:
990 	case ELFSIGN_INVALID_CERTPATH:
991 		es_error(gettext("verification of %s failed."),
992 		    object);
993 		if (cmd_info.verbose)
994 			sig_info_print(esip);
995 		retval = EXIT_VERIFY_FAILED;
996 		break;
997 	case ELFSIGN_NOTSIGNED:
998 		es_error(gettext("no signature found in %s."),
999 		    object);
1000 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
1001 		break;
1002 	default:
1003 		es_error(gettext("unexpected failure attempting verification "
1004 		    "of %s."), object);
1005 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
1006 		break;
1007 	}
1008 
1009 	if (esip != NULL)
1010 		elfsign_sig_info_free(esip);
1011 	if (cmd_info.ess != NULL)
1012 		elfsign_end(cmd_info.ess);
1013 	return (retval);
1014 }
1015 
1016 #define	SET_VALUE(f, s) \
1017 	kmfrv = f; \
1018 	if (kmfrv != KMF_OK) { \
1019 		char *e = NULL; \
1020 		(void) KMF_GetKMFErrorString(kmfrv, &e); \
1021 		cryptoerror(LOG_STDERR, \
1022 			gettext("Failed to %s: %s\n"), \
1023 			s, (e ? e : "unknown error")); \
1024 		if (e) free(e); \
1025 		goto cleanup; \
1026 	}
1027 
1028 static KMF_RETURN
1029 create_csr(char *dn)
1030 {
1031 	KMF_RETURN kmfrv = KMF_OK;
1032 	KMF_HANDLE_T kmfhandle = NULL;
1033 	KMF_CREATEKEYPAIR_PARAMS kp_params;
1034 	KMF_KEY_HANDLE pubk, prik;
1035 	KMF_X509_NAME csrSubject;
1036 	KMF_CSR_DATA csr;
1037 	KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
1038 	KMF_DATA signedCsr = { NULL, 0 };
1039 	KMF_CONFIG_PARAMS config;
1040 	char *err;
1041 
1042 	if ((kmfrv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
1043 		(void) KMF_GetKMFErrorString(kmfrv, &err);
1044 		cryptoerror(LOG_STDERR,
1045 		    gettext("Error initializing KMF: %s\n"),
1046 		    (err ? err : "unknown error"));
1047 		if (err)
1048 			free(err);
1049 		return (kmfrv);
1050 	}
1051 	(void) memset(&csr, 0, sizeof (csr));
1052 	(void) memset(&csrSubject, 0, sizeof (csrSubject));
1053 	(void) memset(&kp_params, 0, sizeof (kp_params));
1054 
1055 	if (cmd_info.privpath != NULL) {
1056 		kp_params.kstype = KMF_KEYSTORE_OPENSSL;
1057 		kp_params.sslparms.keyfile = cmd_info.privpath;
1058 		kp_params.sslparms.format = KMF_FORMAT_ASN1;
1059 	} else if (cmd_info.token_label != NULL) {
1060 
1061 		/* Get a PIN to store the private key in the token */
1062 		char *pin = getpin();
1063 
1064 		if (pin == NULL) {
1065 			(void) KMF_Finalize(kmfhandle);
1066 			return (KMF_ERR_AUTH_FAILED);
1067 		}
1068 
1069 		kp_params.kstype = KMF_KEYSTORE_PK11TOKEN;
1070 		kp_params.cred.cred = pin;
1071 		kp_params.cred.credlen = strlen(pin);
1072 
1073 		(void) memset(&config, 0, sizeof (config));
1074 		config.kstype = KMF_KEYSTORE_PK11TOKEN;
1075 		config.pkcs11config.label = cmd_info.token_label;
1076 		config.pkcs11config.readonly = FALSE;
1077 		kmfrv = KMF_ConfigureKeystore(kmfhandle, &config);
1078 		if (kmfrv != KMF_OK) {
1079 			goto cleanup;
1080 		}
1081 	}
1082 
1083 	/* Create the RSA keypair */
1084 	kp_params.keytype = KMF_RSA;
1085 	kp_params.keylength = ES_DEFAULT_KEYSIZE;
1086 
1087 	kmfrv = KMF_CreateKeypair(kmfhandle, &kp_params, &prik, &pubk);
1088 	if (kmfrv != KMF_OK) {
1089 		(void) KMF_GetKMFErrorString(kmfrv, &err);
1090 		if (err != NULL) {
1091 			cryptoerror(LOG_STDERR,
1092 			    gettext("Create RSA keypair failed: %s"), err);
1093 			free(err);
1094 		}
1095 		goto cleanup;
1096 	}
1097 
1098 	kmfrv = KMF_DNParser(dn, &csrSubject);
1099 	if (kmfrv != KMF_OK) {
1100 		(void) KMF_GetKMFErrorString(kmfrv, &err);
1101 		if (err != NULL) {
1102 			cryptoerror(LOG_STDERR,
1103 			    gettext("Error parsing subject name: %s\n"), err);
1104 			free(err);
1105 		}
1106 		goto cleanup;
1107 	}
1108 
1109 	SET_VALUE(KMF_SetCSRPubKey(kmfhandle, &pubk, &csr), "keypair");
1110 
1111 	SET_VALUE(KMF_SetCSRVersion(&csr, 2), "version number");
1112 
1113 	SET_VALUE(KMF_SetCSRSubjectName(&csr, &csrSubject), "subject name");
1114 
1115 	SET_VALUE(KMF_SetCSRSignatureAlgorithm(&csr, sigAlg),
1116 	    "SignatureAlgorithm");
1117 
1118 	if ((kmfrv = KMF_SignCSR(kmfhandle, &csr, &prik, &signedCsr)) ==
1119 	    KMF_OK) {
1120 		kmfrv = KMF_CreateCSRFile(&signedCsr, KMF_FORMAT_PEM,
1121 		    cmd_info.cert);
1122 	}
1123 
1124 cleanup:
1125 	(void) KMF_FreeKMFKey(kmfhandle, &prik);
1126 	(void) KMF_FreeData(&signedCsr);
1127 	(void) KMF_FreeSignedCSR(&csr);
1128 	(void) KMF_Finalize(kmfhandle);
1129 
1130 	return (kmfrv);
1131 }
1132 
1133 static boolean_t
1134 is_restricted(void)
1135 {
1136 	char	nr[80]; /* Non-retail provider? big buffer for l10n */
1137 	char	*yeschar = nl_langinfo(YESSTR);
1138 	char	*nochar = nl_langinfo(NOSTR);
1139 
1140 	/*
1141 	 * Find out if user will need an activation file.
1142 	 * These questions cover cases #1 and #2 from the Jumbo Export
1143 	 * Control case.  The logic of these questions should not be modified
1144 	 * without consulting the jumbo case, unless there is a new
1145 	 * export case or a change in export/import regulations for Sun
1146 	 * and Sun customers.
1147 	 * Case #3 should be covered in the developer documentation.
1148 	 */
1149 /* BEGIN CSTYLED */
1150 	(void) fprintf(stdout, gettext("\n"
1151 "The government of the United States of America restricts the export of \n"
1152 "\"open cryptographic interfaces\", also known as \"crypto-with-a-hole\".\n"
1153 "Due to this restriction, all providers for the Solaris cryptographic\n"
1154 "framework must be signed, regardless of the country of origin.\n\n"));
1155 
1156 	(void) fprintf(stdout, gettext(
1157 "The terms \"retail\" and \"non-retail\" refer to export classifications \n"
1158 "for products manufactured in the USA.  These terms define the portion of the\n"
1159 "world where the product may be shipped.  Roughly speaking, \"retail\" is \n"
1160 "worldwide (minus certain excluded nations) and \"non-retail\" is domestic \n"
1161 "only (plus some highly favored nations).  If your provider is subject to\n"
1162 "USA export control, then you must obtain an export approval (classification)\n"
1163 "from the government of the USA before exporting your provider.  It is\n"
1164 "critical that you specify the obtained (or expected, when used during \n"
1165 "development) classification to the following questions so that your provider\n"
1166 "will be appropriately signed.\n\n"));
1167 
1168 	for (;;) {
1169 		(void) fprintf(stdout, gettext(
1170 "Do you have retail export approval for use without restrictions based \n"
1171 "on the caller (for example, IPsec)? [Yes/No] "));
1172 /* END CSTYLED */
1173 
1174 		(void) fflush(stdout);
1175 
1176 		(void) fgets(nr, sizeof (nr), stdin);
1177 		if (nr == NULL)
1178 			goto demand_answer;
1179 
1180 		nr[strlen(nr) - 1] = '\0';
1181 
1182 		if (strncasecmp(nochar, nr, 1) == 0) {
1183 /* BEGIN CSTYLED */
1184 			(void) fprintf(stdout, gettext("\n"
1185 "If you have non-retail export approval for unrestricted use of your provider\n"
1186 "by callers, are you also planning to receive retail approval by restricting \n"
1187 "which export sensitive callers (for example, IPsec) may use your \n"
1188 "provider? [Yes/No] "));
1189 /* END CSTYLED */
1190 
1191 			(void) fflush(stdout);
1192 
1193 			(void) fgets(nr, sizeof (nr), stdin);
1194 
1195 			/*
1196 			 * flush standard input so any remaining text
1197 			 * does not affect next read.
1198 			 */
1199 			(void) fflush(stdin);
1200 
1201 			if (nr == NULL)
1202 				goto demand_answer;
1203 
1204 			nr[strlen(nr) - 1] = '\0';
1205 
1206 			if (strncasecmp(nochar, nr, 1) == 0) {
1207 				return (B_FALSE);
1208 			} else if (strncasecmp(yeschar, nr, 1) == 0) {
1209 				return (B_TRUE);
1210 			} else
1211 				goto demand_answer;
1212 
1213 		} else if (strncasecmp(yeschar, nr, 1) == 0) {
1214 			return (B_FALSE);
1215 		}
1216 
1217 	demand_answer:
1218 		(void) fprintf(stdout,
1219 		    gettext("You must specify an answer.\n\n"));
1220 	}
1221 }
1222 
1223 #define	CN_MAX_LENGTH	64	/* Verisign implementation limit */
1224 /*
1225  * Generate a certificate request into the file named cmd_info.cert
1226  */
1227 /*ARGSUSED*/
1228 static ret_t
1229 do_cert_request(char *object)
1230 {
1231 	const char	 PartnerDNFMT[] =
1232 	    "CN=%s, "
1233 	    "OU=Class B, "
1234 	    "%sOU=Solaris Cryptographic Framework, "
1235 	    "OU=Partner Object Signing, "
1236 	    "O=Sun Microsystems Inc";
1237 	const char	 SunCDNFMT[] =
1238 	    "CN=%s, "
1239 	    "OU=Class B, "
1240 	    "%sOU=Solaris Cryptographic Framework, "
1241 	    "OU=Corporate Object Signing, "
1242 	    "O=Sun Microsystems Inc";
1243 	const char	 SunSDNFMT[] =
1244 	    "CN=%s, "
1245 	    "OU=Class B, "
1246 	    "%sOU=Solaris Signed Execution, "
1247 	    "OU=Corporate Object Signing, "
1248 	    "O=Sun Microsystems Inc";
1249 	const char	 *dnfmt = NULL;
1250 	char	cn[CN_MAX_LENGTH + 1];
1251 	char	*dn = NULL;
1252 	size_t	dn_len;
1253 	char	*restriction = "";
1254 	KMF_RETURN   kmfret;
1255 	cryptodebug("do_cert_request");
1256 
1257 	/*
1258 	 * Get the DN prefix from the user
1259 	 */
1260 	switch (cmd_info.internal_req) {
1261 	case 'c':
1262 		dnfmt = SunCDNFMT;
1263 		(void) fprintf(stdout, gettext(
1264 		    "Enter Sun Microsystems, Inc. Release name.\n"
1265 		    "This will be the prefix of the Certificate DN: "));
1266 		break;
1267 	case 's':
1268 		dnfmt = SunSDNFMT;
1269 		(void) fprintf(stdout, gettext(
1270 		    "Enter Sun Microsystems, Inc. Release name.\n"
1271 		    "This will be the prefix of the Certificate DN: "));
1272 		break;
1273 	default:
1274 		dnfmt = PartnerDNFMT;
1275 		(void) fprintf(stdout, gettext(
1276 		    "Enter Company Name / Stock Symbol"
1277 		    " or some other globally unique identifier.\n"
1278 		    "This will be the prefix of the Certificate DN: "));
1279 		break;
1280 	}
1281 
1282 	(void) fgets(cn, sizeof (cn), stdin);
1283 	if ((cn == NULL) || (cn[0] == '\n')) {
1284 		es_error(gettext("you must specify a Certificate DN prefix"));
1285 		return (EXIT_INVALID_ARG);
1286 	}
1287 
1288 	if (cn[strlen(cn) - 1] == '\n') {
1289 		cn[strlen(cn) - 1] = '\0';	/* chop trailing \n */
1290 	} else {
1291 		es_error(gettext("You must specify a Certificate DN prefix "
1292 		    "of no more than %d characters"), CN_MAX_LENGTH);
1293 		return (EXIT_INVALID_ARG);
1294 	}
1295 
1296 	/*
1297 	 * determine if there is an export restriction
1298 	 */
1299 	switch (cmd_info.internal_req) {
1300 	case 's':
1301 		restriction = "";
1302 		break;
1303 	default:
1304 		restriction = is_restricted() ? USAGELIMITED ", " : "";
1305 		break;
1306 	}
1307 
1308 	/* Update DN string */
1309 	dn_len = strlen(cn) + strlen(dnfmt) + strlen(restriction);
1310 	dn = malloc(dn_len + 1);
1311 	(void) snprintf(dn, dn_len, dnfmt, cn, restriction);
1312 
1313 	cryptodebug("Generating Certificate request for DN: %s", dn);
1314 	kmfret = create_csr(dn);
1315 	free(dn);
1316 	if (kmfret == KMF_OK)
1317 		return (EXIT_OKAY);
1318 	else
1319 		return (EXIT_CSR_FAILED);
1320 }
1321 
1322 static void
1323 str_print(char *s)
1324 {
1325 	if (s == NULL)
1326 		return;
1327 	(void) fprintf(stdout, "%s\n", s);
1328 }
1329 
1330 /*ARGSUSED*/
1331 static ret_t
1332 do_list(char *object)
1333 {
1334 	ret_t	retval;
1335 
1336 	if (cmd_info.elfcnt > 0) {
1337 		ELFsign_status_t	elfstat;
1338 		struct filesignatures	*fssp = NULL;
1339 		size_t fs_len;
1340 		struct ELFsign_sig_info	*esip;
1341 
1342 		if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
1343 			return (retval);
1344 		elfstat = elfsign_signatures(cmd_info.ess,
1345 		    &fssp, &fs_len, ES_GET);
1346 		if (elfstat == ELFSIGN_SUCCESS) {
1347 			retval = EXIT_OKAY;
1348 			if (elfsign_sig_info(fssp, &esip)) {
1349 				switch (cmd_info.field) {
1350 				case FLD_FORMAT:
1351 					str_print(esip->esi_format);
1352 					break;
1353 				case FLD_SIGNER:
1354 					str_print(esip->esi_signer);
1355 					break;
1356 				case FLD_TIME:
1357 					if (esip->esi_time == 0)
1358 						retval = EXIT_INVALID_ARG;
1359 					else
1360 						str_print(time_str(
1361 						    esip->esi_time));
1362 					break;
1363 				default:
1364 					retval = EXIT_INVALID_ARG;
1365 				}
1366 				elfsign_sig_info_free(esip);
1367 			}
1368 			free(fssp);
1369 		} else
1370 			retval = EXIT_VERIFY_FAILED_UNSIGNED;
1371 		elfsign_end(cmd_info.ess);
1372 	} else {
1373 		ELFCert_t	cert;
1374 		/*
1375 		 * Initialize the ESS record here even though we are not
1376 		 * actually opening any ELF files.
1377 		 */
1378 		if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
1379 		    ELFSIGN_SUCCESS)
1380 			return (EXIT_MEMORY_ERROR);
1381 
1382 		if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
1383 		    &cert, cmd_info.es_action)) {
1384 			retval = EXIT_OKAY;
1385 			switch (cmd_info.field) {
1386 			case FLD_SUBJECT:
1387 				str_print(elfcertlib_getdn(cert));
1388 				break;
1389 			case FLD_ISSUER:
1390 				str_print(elfcertlib_getissuer(cert));
1391 				break;
1392 			default:
1393 				retval = EXIT_INVALID_ARG;
1394 			}
1395 			elfcertlib_releasecert(cmd_info.ess, cert);
1396 		} else
1397 			retval = EXIT_BAD_CERT;
1398 		elfsign_end(cmd_info.ess);
1399 	}
1400 
1401 	return (retval);
1402 }
1403 
1404 static void
1405 es_error(const char *fmt, ...)
1406 {
1407 	char msgbuf[BUFSIZ];
1408 	va_list	args;
1409 
1410 	va_start(args, fmt);
1411 	(void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
1412 	va_end(args);
1413 	(void) fflush(stdout);
1414 	cryptoerror(LOG_STDERR, "%s", msgbuf);
1415 	(void) fflush(stderr);
1416 }
1417 
1418 static char *
1419 time_str(time_t t)
1420 {
1421 	static char	buf[80];
1422 	char		*bufp;
1423 
1424 	bufp = buf;
1425 	if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
1426 		bufp = ctime(&t);
1427 	return (bufp);
1428 }
1429 
1430 static void
1431 sig_info_print(struct ELFsign_sig_info *esip)
1432 {
1433 	if (esip == NULL)
1434 		return;
1435 	(void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
1436 	(void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
1437 	if (esip->esi_time == 0)
1438 		return;
1439 	(void) fprintf(stdout, gettext("signed on: %s.\n"),
1440 	    time_str(esip->esi_time));
1441 }
1442