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