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