xref: /titanic_41/usr/src/cmd/cmd-crypto/elfsign/elfsign.c (revision 5203bc321053fb87d7073c7640548fab73634793)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Developer command for adding the signature section to an ELF object
28  * PSARC 2001/488
29  *
30  * DEBUG Information:
31  * This command uses the cryptodebug() function from libcryptoutil.
32  * Set SUNW_CRYPTO_DEBUG to stderr or syslog for all debug to go to auth.debug
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <limits.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <libintl.h>
45 #include <locale.h>
46 #include <errno.h>
47 #include <strings.h>
48 
49 #include <cryptoutil.h>
50 #include <sys/crypto/elfsign.h>
51 #include <libelfsign.h>
52 
53 #include <kmfapi.h>
54 
55 #define	SIGN		"sign"
56 #define	SIGN_OPTS	"c:e:F:k:P:T:v"
57 #define	VERIFY		"verify"
58 #define	VERIFY_OPTS	"c:e:v"
59 #define	REQUEST		"request"
60 #define	REQUEST_OPTS	"i:k:r:T:"
61 #define	LIST		"list"
62 #define	LIST_OPTS	"c:e:f:"
63 
64 enum cmd_e {
65 	ES_SIGN,
66 	ES_VERIFY,
67 	ES_REQUEST,
68 	ES_LIST
69 };
70 
71 enum field_e {
72 	FLD_UNKNOWN,
73 	FLD_SUBJECT,
74 	FLD_ISSUER,
75 	FLD_FORMAT,
76 	FLD_SIGNER,
77 	FLD_TIME
78 };
79 
80 #define	MIN_ARGS	3	/* The minimum # args to do anything */
81 #define	ES_DEFAULT_KEYSIZE 1024
82 
83 static struct {
84 	enum cmd_e	cmd;	/* sub command: sign | verify | request */
85 	char	*cert;		/* -c <certificate_file> | */
86 				/* -r <certificate_request_file> */
87 	char	**elfobj;	/* -e <elf_object> */
88 	int	elfcnt;
89 	enum ES_ACTION	es_action;
90 	ELFsign_t	ess;	/* libelfsign opaque "state" */
91 	int	extracnt;
92 	enum field_e	field;	/* -f <field> */
93 	char internal_req;	/* Sun internal certificate request */
94 	char	*pinpath;	/* -P <pin> */
95 	char	*privpath;	/* -k <private_key> */
96 	char	*token_label;	/* -T <token_label> */
97 	boolean_t verbose;	/* chatty output */
98 } cmd_info;
99 
100 enum ret_e {
101 	EXIT_OKAY,
102 	EXIT_INVALID_ARG,
103 	EXIT_VERIFY_FAILED,
104 	EXIT_CANT_OPEN_ELF_OBJECT,
105 	EXIT_BAD_CERT,
106 	EXIT_BAD_PRIVATEKEY,
107 	EXIT_SIGN_FAILED,
108 	EXIT_VERIFY_FAILED_UNSIGNED,
109 	EXIT_CSR_FAILED,
110 	EXIT_MEMORY_ERROR
111 };
112 
113 struct field_s {
114 	char	*name;
115 	enum field_e	field;
116 } fields[] = {
117 	{ "subject", FLD_SUBJECT },
118 	{ "issuer", FLD_ISSUER },
119 	{ "format", FLD_FORMAT },
120 	{ "signer", FLD_SIGNER },
121 	{ "time", FLD_TIME },
122 	NULL, 0
123 };
124 
125 typedef enum ret_e ret_t;
126 
127 static void usage(void);
128 static ret_t getelfobj(char *);
129 static char *getpin(void);
130 static ret_t do_sign(char *);
131 static ret_t do_verify(char *);
132 static ret_t do_cert_request(char *);
133 static ret_t do_list(char *);
134 static void es_error(const char *fmt, ...);
135 static char *time_str(time_t t);
136 static void sig_info_print(struct ELFsign_sig_info *esip);
137 
138 int
139 main(int argc, char **argv)
140 {
141 	extern char *optarg;
142 	char *scmd = NULL;
143 	char *opts;		/* The set of flags for cmd */
144 	int errflag = 0;	/* We had an options parse error */
145 	char c;			/* current getopts flag */
146 	ret_t (*action)(char *);	/* Function pointer for the action */
147 	ret_t ret;
148 
149 	(void) setlocale(LC_ALL, "");
150 #if !defined(TEXT_DOMAIN)	/* Should be defiend by cc -D */
151 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
152 #endif
153 	(void) textdomain(TEXT_DOMAIN);
154 
155 	cryptodebug_init("elfsign");
156 
157 	if (argc < MIN_ARGS) {
158 		es_error(gettext("invalid number of arguments"));
159 		usage();
160 		return (EXIT_INVALID_ARG);
161 	}
162 
163 	scmd = argv[1];
164 	cmd_info.cert = NULL;
165 	cmd_info.elfobj = NULL;
166 	cmd_info.elfcnt = 0;
167 	cmd_info.es_action = ES_GET;
168 	cmd_info.ess = NULL;
169 	cmd_info.extracnt = 0;
170 	cmd_info.field = FLD_UNKNOWN;
171 	cmd_info.internal_req = '\0';
172 	cmd_info.pinpath = NULL;
173 	cmd_info.privpath = NULL;
174 	cmd_info.token_label = NULL;
175 	cmd_info.verbose = B_FALSE;
176 
177 	if (strcmp(scmd, SIGN) == 0) {
178 		cmd_info.cmd = ES_SIGN;
179 		opts = SIGN_OPTS;
180 		cryptodebug("cmd=sign opts=%s", opts);
181 		action = do_sign;
182 		cmd_info.es_action = ES_UPDATE_RSA_SHA1;
183 	} else if (strcmp(scmd, VERIFY) == 0) {
184 		cmd_info.cmd = ES_VERIFY;
185 		opts = VERIFY_OPTS;
186 		cryptodebug("cmd=verify opts=%s", opts);
187 		action = do_verify;
188 	} else if (strcmp(scmd, REQUEST) == 0) {
189 		cmd_info.cmd = ES_REQUEST;
190 		opts = REQUEST_OPTS;
191 		cryptodebug("cmd=request opts=%s", opts);
192 		action = do_cert_request;
193 	} else if (strcmp(scmd, LIST) == 0) {
194 		cmd_info.cmd = ES_LIST;
195 		opts = LIST_OPTS;
196 		cryptodebug("cmd=list opts=%s", opts);
197 		action = do_list;
198 	} else {
199 		es_error(gettext("Unknown sub-command: %s"),
200 		    scmd);
201 		usage();
202 		return (EXIT_INVALID_ARG);
203 	}
204 
205 	/*
206 	 * Note:  There is no need to check that optarg isn't NULL
207 	 *	  because getopt does that for us.
208 	 */
209 	while (!errflag && (c = getopt(argc - 1, argv + 1, opts)) != EOF) {
210 		if (strchr("ceFihkPTr", c) != NULL)
211 			cryptodebug("c=%c, '%s'", c, optarg);
212 		else
213 			cryptodebug("c=%c", c);
214 
215 		switch (c) {
216 		case 'c':
217 			cmd_info.cert = optarg;
218 			break;
219 		case 'e':
220 			cmd_info.elfcnt++;
221 			cmd_info.elfobj = (char **)realloc(cmd_info.elfobj,
222 			    sizeof (char *) * cmd_info.elfcnt);
223 			if (cmd_info.elfobj == NULL) {
224 				es_error(gettext(
225 				    "Too many elf objects specified."));
226 				return (EXIT_INVALID_ARG);
227 			}
228 			cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg;
229 			break;
230 		case 'f':
231 			{
232 				struct field_s	*fp;
233 				cmd_info.field = FLD_UNKNOWN;
234 				for (fp = fields; fp->name != NULL; fp++) {
235 					if (strcasecmp(optarg, fp->name) == 0) {
236 						cmd_info.field = fp->field;
237 						break;
238 					}
239 				}
240 				if (cmd_info.field == FLD_UNKNOWN) {
241 					cryptodebug("Invalid field option");
242 					errflag++;
243 				}
244 			}
245 			break;
246 		case 'F':
247 			if (strcasecmp(optarg, ES_FMT_RSA_MD5_SHA1) == 0)
248 				cmd_info.es_action = ES_UPDATE_RSA_MD5_SHA1;
249 			else if (strcasecmp(optarg, ES_FMT_RSA_SHA1) == 0)
250 				cmd_info.es_action = ES_UPDATE_RSA_SHA1;
251 			else {
252 				cryptodebug("Invalid format option");
253 				errflag++;
254 			}
255 			break;
256 		case 'i':	 /* Undocumented internal Sun use only */
257 			cmd_info.internal_req = *optarg;
258 			break;
259 		case 'k':
260 			cmd_info.privpath = optarg;
261 			if (cmd_info.token_label != NULL ||
262 			    cmd_info.pinpath != NULL)
263 				errflag++;
264 			break;
265 		case 'P':
266 			cmd_info.pinpath = optarg;
267 			if (cmd_info.privpath != NULL)
268 				errflag++;
269 			break;
270 		case 'r':
271 			cmd_info.cert = optarg;
272 			break;
273 		case 'T':
274 			cmd_info.token_label = optarg;
275 			if (cmd_info.privpath != NULL)
276 				errflag++;
277 			break;
278 		case 'v':
279 			cmd_info.verbose = B_TRUE;
280 			break;
281 		default:
282 			errflag++;
283 		}
284 	}
285 
286 	optind++;	/* we skipped over subcommand */
287 	cmd_info.extracnt = argc - optind;
288 
289 	if (cmd_info.extracnt != 0 &&
290 	    cmd_info.cmd != ES_SIGN && cmd_info.cmd != ES_VERIFY) {
291 		cryptodebug("Extra arguments, optind=%d, argc=%d",
292 		    optind, argc);
293 		errflag++;
294 	}
295 
296 	switch (cmd_info.cmd) {
297 	case ES_VERIFY:
298 		if (cmd_info.elfcnt + argc - optind == 0) {
299 			cryptodebug("Missing elfobj");
300 			errflag++;
301 		}
302 		break;
303 
304 	case ES_SIGN:
305 		if (((cmd_info.privpath == NULL) &&
306 		    (cmd_info.token_label == NULL)) ||
307 		    (cmd_info.cert == NULL) ||
308 		    (cmd_info.elfcnt + argc - optind == 0)) {
309 			cryptodebug("Missing privpath|token_label/cert/elfobj");
310 			errflag++;
311 		}
312 		break;
313 
314 	case ES_REQUEST:
315 		if (((cmd_info.privpath == NULL) &&
316 		    (cmd_info.token_label == NULL)) ||
317 		    (cmd_info.cert == NULL)) {
318 			cryptodebug("Missing privpath|token_label/certreq");
319 			errflag++;
320 		}
321 		break;
322 	case ES_LIST:
323 		if ((cmd_info.cert != NULL) == (cmd_info.elfcnt > 0)) {
324 			cryptodebug("Neither or both of cert/elfobj");
325 			errflag++;
326 		}
327 		break;
328 	}
329 
330 	if (errflag) {
331 		usage();
332 		return (EXIT_INVALID_ARG);
333 	}
334 
335 	switch (cmd_info.cmd) {
336 	case ES_REQUEST:
337 	case ES_LIST:
338 		ret = action(NULL);
339 		break;
340 	default:
341 		{
342 		int i;
343 		ret_t	iret;
344 
345 		ret = EXIT_OKAY;
346 		iret = EXIT_OKAY;
347 		for (i = 0; i < cmd_info.elfcnt &&
348 		    (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
349 			iret = action(cmd_info.elfobj[i]);
350 			if (iret > ret)
351 				ret = iret;
352 		}
353 		for (i = optind; i < argc &&
354 		    (ret == EXIT_OKAY || cmd_info.cmd != ES_SIGN); i++) {
355 			iret = action(argv[i]);
356 			if (iret > ret)
357 				ret = iret;
358 		}
359 		break;
360 		}
361 	}
362 
363 	if (cmd_info.elfobj != NULL)
364 		free(cmd_info.elfobj);
365 
366 	return (ret);
367 }
368 
369 
370 static void
371 usage(void)
372 {
373 /* BEGIN CSTYLED */
374 	(void) fprintf(stderr, gettext(
375  "usage:\n"
376  "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n"
377  "\t\t[-F <format>] -k <private_key_file> [elf_object]..."
378  "\n"
379  "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n"
380  "\t\t[-F <format>] -T <token_label> [-P <pin_file>] [elf_object]..."
381  "\n\n"
382  "\telfsign verify [-v] [-c <certificate_file>] [-e <elf_object>]\n"
383  "\t\t[elf_object]..."
384  "\n\n"
385  "\telfsign request -r <certificate_request_file> -k <private_key_file>"
386  "\n"
387  "\telfsign request -r <certificate_request_file> -T <token_label>"
388  "\n\n"
389  "\telfsign list -f field -c <certificate_file>"
390  "\n"
391  "\telfsign list -f field -e <elf_object>"
392  "\n"));
393 /* END CSTYLED */
394 }
395 
396 static ret_t
397 getelfobj(char *elfpath)
398 {
399 	ELFsign_status_t estatus;
400 	ret_t	ret = EXIT_SIGN_FAILED;
401 
402 	estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess));
403 	switch (estatus) {
404 	case ELFSIGN_SUCCESS:
405 		ret = EXIT_OKAY;
406 		break;
407 	case ELFSIGN_INVALID_ELFOBJ:
408 		es_error(gettext(
409 		    "Unable to open %s as an ELF object."),
410 		    elfpath);
411 		ret = EXIT_CANT_OPEN_ELF_OBJECT;
412 		break;
413 	default:
414 		es_error(gettext("unexpected failure: %d"), estatus);
415 		if (cmd_info.cmd == ES_SIGN) {
416 			ret = EXIT_SIGN_FAILED;
417 		} else if (cmd_info.cmd == ES_VERIFY) {
418 			ret = EXIT_VERIFY_FAILED;
419 		}
420 	}
421 
422 	return (ret);
423 }
424 
425 static ret_t
426 setcertpath(void)
427 {
428 	ELFsign_status_t estatus;
429 	ret_t	ret = EXIT_SIGN_FAILED;
430 
431 	if (cmd_info.cert == NULL)
432 		return (EXIT_OKAY);
433 	estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert);
434 	switch (estatus) {
435 	case ELFSIGN_SUCCESS:
436 		ret = EXIT_OKAY;
437 		break;
438 	case ELFSIGN_INVALID_CERTPATH:
439 		if (cmd_info.cert != NULL) {
440 			es_error(gettext("Unable to open %s as a certificate."),
441 			    cmd_info.cert);
442 		}
443 		ret = EXIT_BAD_CERT;
444 		break;
445 	default:
446 		es_error(gettext("unusable certificate: %s"), cmd_info.cert);
447 		if (cmd_info.cmd == ES_SIGN) {
448 			ret = EXIT_SIGN_FAILED;
449 		} else if (cmd_info.cmd == ES_VERIFY) {
450 			ret = EXIT_VERIFY_FAILED;
451 		}
452 	}
453 
454 	return (ret);
455 }
456 
457 /*
458  * getpin - return pointer to token PIN in static storage
459  */
460 static char *
461 getpin(void)
462 {
463 	static char	pinbuf[PASS_MAX + 1];
464 	char	*pp;
465 	FILE	*pinfile;
466 
467 	if (cmd_info.pinpath == NULL)
468 		return (getpassphrase(
469 		    gettext("Enter PIN for PKCS#11 token: ")));
470 	if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) {
471 		es_error(gettext("failed to open %s."),
472 		    cmd_info.pinpath);
473 		return (NULL);
474 	}
475 
476 	pp = fgets(pinbuf, sizeof (pinbuf), pinfile);
477 	(void) fclose(pinfile);
478 	if (pp == NULL) {
479 		es_error(gettext("failed to read PIN from %s."),
480 		    cmd_info.pinpath);
481 		return (NULL);
482 	}
483 	pp = &pinbuf[strlen(pinbuf) - 1];
484 	if (*pp == '\n')
485 		*pp = '\0';
486 	return (pinbuf);
487 }
488 
489 /*
490  * Add the .SUNW_signature sections for the ELF signature
491  */
492 static ret_t
493 do_sign(char *object)
494 {
495 	ret_t 	ret;
496 	ELFsign_status_t	elfstat;
497 	struct filesignatures	*fssp = NULL;
498 	size_t fs_len;
499 	uchar_t sig[SIG_MAX_LENGTH];
500 	size_t	sig_len = SIG_MAX_LENGTH;
501 	uchar_t	hash[SIG_MAX_LENGTH];
502 	size_t	hash_len = SIG_MAX_LENGTH;
503 	ELFCert_t	cert = NULL;
504 	char	*dn;
505 	size_t	dn_len;
506 
507 	cryptodebug("do_sign");
508 	if ((ret = getelfobj(object)) != EXIT_OKAY)
509 		return (ret);
510 
511 	if (cmd_info.token_label &&
512 	    !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) {
513 		es_error(gettext("Unable to access token: %s"),
514 		    cmd_info.token_label);
515 		ret = EXIT_SIGN_FAILED;
516 		goto cleanup;
517 	}
518 
519 	if ((ret = setcertpath()) != EXIT_OKAY)
520 		goto cleanup;
521 
522 	if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
523 	    cmd_info.es_action)) {
524 		es_error(gettext("Unable to load certificate: %s"),
525 		    cmd_info.cert);
526 		ret = EXIT_BAD_CERT;
527 		goto cleanup;
528 	}
529 
530 	if (cmd_info.privpath != NULL) {
531 		if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
532 		    cmd_info.privpath)) {
533 			es_error(gettext("Unable to load private key: %s"),
534 			    cmd_info.privpath);
535 			ret = EXIT_BAD_PRIVATEKEY;
536 			goto cleanup;
537 		}
538 	} else {
539 		char *pin = getpin();
540 		if (pin == NULL) {
541 			es_error(gettext("Unable to get PIN"));
542 			ret = EXIT_BAD_PRIVATEKEY;
543 			goto cleanup;
544 		}
545 		if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
546 		    cmd_info.token_label, pin)) {
547 			es_error(gettext("Unable to access private key "
548 			    "in token %s"), cmd_info.token_label);
549 			ret = EXIT_BAD_PRIVATEKEY;
550 			goto cleanup;
551 		}
552 	}
553 
554 	/*
555 	 * Get the DN from the certificate.
556 	 */
557 	if ((dn = elfcertlib_getdn(cert)) == NULL) {
558 		es_error(gettext("Unable to find DN in certificate %s"),
559 		    cmd_info.cert);
560 		ret = EXIT_SIGN_FAILED;
561 		goto cleanup;
562 	}
563 	dn_len = strlen(dn);
564 	cryptodebug("DN = %s", dn);
565 
566 	elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET);
567 	if (elfstat != ELFSIGN_SUCCESS) {
568 		if (elfstat != ELFSIGN_NOTSIGNED) {
569 			es_error(gettext("Unable to retrieve existing "
570 			    "signature block in %s"), object);
571 			ret = EXIT_SIGN_FAILED;
572 			goto cleanup;
573 		}
574 		fssp = NULL;
575 		/*
576 		 * force creation and naming of signature section
577 		 * so the hash doesn't change
578 		 */
579 		if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
580 		    cmd_info.es_action) != ELFSIGN_SUCCESS) {
581 			es_error(gettext("Unable to insert "
582 			    "signature block into %s"), object);
583 			ret = EXIT_SIGN_FAILED;
584 			goto cleanup;
585 		}
586 	}
587 
588 	bzero(hash, sizeof (hash));
589 	if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
590 		es_error(gettext("Unable to calculate hash of ELF object %s"),
591 		    object);
592 		ret = EXIT_SIGN_FAILED;
593 		goto cleanup;
594 	}
595 
596 	bzero(sig, sizeof (sig));
597 	if (!elfcertlib_sign(cmd_info.ess, cert,
598 	    hash, hash_len, sig, &sig_len)) {
599 		es_error(gettext("Unable to sign %s using key from %s"),
600 		    object, cmd_info.privpath ?
601 		    cmd_info.privpath : cmd_info.token_label);
602 		ret = EXIT_SIGN_FAILED;
603 		goto cleanup;
604 	}
605 
606 	{ /* DEBUG START */
607 		const int sigstr_len = sizeof (char) * sig_len * 2 + 1;
608 		char *sigstr = malloc(sigstr_len);
609 
610 		tohexstr(sig, sig_len, sigstr, sigstr_len);
611 		cryptodebug("sig value is: %s", sigstr);
612 		free(sigstr);
613 	} /* DEBUG END */
614 
615 	fssp = elfsign_insert_dso(cmd_info.ess, fssp,
616 	    dn, dn_len, sig, sig_len, NULL, 0);
617 	if (fssp == NULL) {
618 		es_error(gettext("Unable to prepare signature for %s"),
619 		    object);
620 		ret = EXIT_SIGN_FAILED;
621 		goto cleanup;
622 	}
623 	if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
624 	    cmd_info.es_action) != ELFSIGN_SUCCESS) {
625 		es_error(gettext("Unable to update %s: with signature"),
626 		    object);
627 		ret = EXIT_SIGN_FAILED;
628 		goto cleanup;
629 	}
630 	if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) {
631 		(void) fprintf(stdout,
632 		    gettext("elfsign: %s signed successfully.\n"),
633 		    object);
634 	}
635 	if (cmd_info.verbose) {
636 		struct ELFsign_sig_info *esip;
637 
638 		if (elfsign_sig_info(fssp, &esip)) {
639 			sig_info_print(esip);
640 			elfsign_sig_info_free(esip);
641 		}
642 	}
643 
644 	ret = EXIT_OKAY;
645 
646 cleanup:
647 	free(fssp);
648 	bzero(sig, sig_len);
649 	bzero(hash, hash_len);
650 
651 	if (cert != NULL)
652 		elfcertlib_releasecert(cmd_info.ess, cert);
653 	if (cmd_info.ess != NULL)
654 		elfsign_end(cmd_info.ess);
655 
656 	return (ret);
657 }
658 
659 /*
660  * Verify the signature of the object
661  * This subcommand is intended to be used by developers during their build
662  * processes.  Therefore we can not assume that the certificate is in
663  * /etc/crypto/certs so we must use the path we got from the commandline.
664  */
665 static ret_t
666 do_verify(char *object)
667 {
668 	ELFsign_status_t res;
669 	struct ELFsign_sig_info	*esip;
670 	ret_t	retval;
671 
672 	cryptodebug("do_verify");
673 	if ((retval = getelfobj(object)) != EXIT_OKAY)
674 		return (retval);
675 
676 	if ((retval = setcertpath()) != EXIT_OKAY) {
677 		elfsign_end(cmd_info.ess);
678 		return (retval);
679 	}
680 
681 	res = elfsign_verify_signature(cmd_info.ess, &esip);
682 	switch (res) {
683 	case ELFSIGN_SUCCESS:
684 		(void) fprintf(stdout,
685 		    gettext("elfsign: verification of %s passed.\n"),
686 		    object);
687 		if (cmd_info.verbose)
688 			sig_info_print(esip);
689 		retval = EXIT_OKAY;
690 		break;
691 	case ELFSIGN_FAILED:
692 	case ELFSIGN_INVALID_CERTPATH:
693 		es_error(gettext("verification of %s failed."),
694 		    object);
695 		if (cmd_info.verbose)
696 			sig_info_print(esip);
697 		retval = EXIT_VERIFY_FAILED;
698 		break;
699 	case ELFSIGN_NOTSIGNED:
700 		es_error(gettext("no signature found in %s."),
701 		    object);
702 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
703 		break;
704 	default:
705 		es_error(gettext("unexpected failure attempting verification "
706 		    "of %s."), object);
707 		retval = EXIT_VERIFY_FAILED_UNSIGNED;
708 		break;
709 	}
710 
711 	if (esip != NULL)
712 		elfsign_sig_info_free(esip);
713 	if (cmd_info.ess != NULL)
714 		elfsign_end(cmd_info.ess);
715 	return (retval);
716 }
717 
718 #define	SET_VALUE(f, s) \
719 	kmfrv = f; \
720 	if (kmfrv != KMF_OK) { \
721 		char *e = NULL; \
722 		(void) kmf_get_kmf_error_str(kmfrv, &e); \
723 		cryptoerror(LOG_STDERR, \
724 			gettext("Failed to %s: %s\n"), \
725 			s, (e ? e : "unknown error")); \
726 		if (e) free(e); \
727 		goto cleanup; \
728 	}
729 
730 static KMF_RETURN
731 create_csr(char *dn)
732 {
733 	KMF_RETURN kmfrv = KMF_OK;
734 	KMF_HANDLE_T kmfhandle = NULL;
735 	KMF_KEY_HANDLE pubk, prik;
736 	KMF_X509_NAME csrSubject;
737 	KMF_CSR_DATA csr;
738 	KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
739 	KMF_DATA signedCsr = { NULL, 0 };
740 	char *err;
741 	KMF_ATTRIBUTE	attrlist[16];
742 	KMF_ENCODE_FORMAT	format;
743 	KMF_KEYSTORE_TYPE	kstype;
744 	KMF_KEY_ALG	keytype;
745 	uint32_t	keylength;
746 	KMF_CREDENTIAL	cred;
747 	char	*pin = NULL;
748 	int	numattr;
749 
750 	if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
751 		(void) kmf_get_kmf_error_str(kmfrv, &err);
752 		cryptoerror(LOG_STDERR,
753 		    gettext("Error initializing KMF: %s\n"),
754 		    (err ? err : "unknown error"));
755 		if (err)
756 			free(err);
757 		return (kmfrv);
758 	}
759 	(void) memset(&csr, 0, sizeof (csr));
760 	(void) memset(&csrSubject, 0, sizeof (csrSubject));
761 
762 	if (cmd_info.privpath != NULL) {
763 		kstype = KMF_KEYSTORE_OPENSSL;
764 		format = KMF_FORMAT_ASN1;
765 	} else {
766 		boolean_t	readonly;
767 		/* args checking verified (cmd_info.token_label != NULL) */
768 
769 		/* Get a PIN to store the private key in the token */
770 		pin = getpin();
771 
772 		if (pin == NULL) {
773 			(void) kmf_finalize(kmfhandle);
774 			return (KMF_ERR_AUTH_FAILED);
775 		}
776 
777 		kstype = KMF_KEYSTORE_PK11TOKEN;
778 		readonly = B_FALSE;
779 
780 		numattr = 0;
781 		kmf_set_attr_at_index(attrlist, numattr++,
782 		    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
783 		kmf_set_attr_at_index(attrlist, numattr++,
784 		    KMF_TOKEN_LABEL_ATTR, cmd_info.token_label,
785 		    strlen(cmd_info.token_label));
786 		kmf_set_attr_at_index(attrlist, numattr++,
787 		    KMF_READONLY_ATTR, &readonly, sizeof (readonly));
788 		kmfrv = kmf_configure_keystore(kmfhandle, numattr, attrlist);
789 		if (kmfrv != KMF_OK) {
790 			goto cleanup;
791 		}
792 	}
793 
794 	/* Create the RSA keypair */
795 	keytype = KMF_RSA;
796 	keylength = ES_DEFAULT_KEYSIZE;
797 	(void) memset(&prik, 0, sizeof (prik));
798 	(void) memset(&pubk, 0, sizeof (pubk));
799 
800 	numattr = 0;
801 	kmf_set_attr_at_index(attrlist, numattr++,
802 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
803 	kmf_set_attr_at_index(attrlist, numattr++,
804 	    KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
805 	kmf_set_attr_at_index(attrlist, numattr++,
806 	    KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
807 	if (pin != NULL) {
808 		cred.cred = pin;
809 		cred.credlen = strlen(pin);
810 		kmf_set_attr_at_index(attrlist, numattr++,
811 		    KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL));
812 	}
813 	kmf_set_attr_at_index(attrlist, numattr++,
814 	    KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE));
815 	kmf_set_attr_at_index(attrlist, numattr++,
816 	    KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE));
817 	if (kstype == KMF_KEYSTORE_OPENSSL) {
818 		kmf_set_attr_at_index(attrlist, numattr++,
819 		    KMF_KEY_FILENAME_ATTR, cmd_info.privpath,
820 		    strlen(cmd_info.privpath));
821 		kmf_set_attr_at_index(attrlist, numattr++,
822 		    KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format));
823 	}
824 
825 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
826 	if (kmfrv != KMF_OK) {
827 		(void) kmf_get_kmf_error_str(kmfrv, &err);
828 		cryptoerror(LOG_STDERR,
829 		    gettext("Create RSA keypair failed: %s"),
830 		    (err ? err : "unknown error"));
831 		free(err);
832 		goto cleanup;
833 	}
834 
835 	kmfrv = kmf_dn_parser(dn, &csrSubject);
836 	if (kmfrv != KMF_OK) {
837 		(void) kmf_get_kmf_error_str(kmfrv, &err);
838 		cryptoerror(LOG_STDERR,
839 		    gettext("Error parsing subject name: %s\n"),
840 		    (err ? err : "unknown error"));
841 		free(err);
842 		goto cleanup;
843 	}
844 
845 	SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair");
846 
847 	SET_VALUE(kmf_set_csr_version(&csr, 2), "version number");
848 
849 	SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name");
850 
851 	SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm");
852 
853 	if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) ==
854 	    KMF_OK) {
855 		kmfrv = kmf_create_csr_file(&signedCsr, KMF_FORMAT_PEM,
856 		    cmd_info.cert);
857 	}
858 
859 cleanup:
860 	(void) kmf_free_kmf_key(kmfhandle, &prik);
861 	(void) kmf_free_data(&signedCsr);
862 	(void) kmf_free_signed_csr(&csr);
863 	(void) kmf_finalize(kmfhandle);
864 
865 	return (kmfrv);
866 }
867 
868 
869 #define	CN_MAX_LENGTH	64	/* Verisign implementation limit */
870 /*
871  * Generate a certificate request into the file named cmd_info.cert
872  */
873 /*ARGSUSED*/
874 static ret_t
875 do_cert_request(char *object)
876 {
877 	const char	 PartnerDNFMT[] =
878 	    "CN=%s, "
879 	    "OU=Class B, "
880 	    "OU=Solaris Cryptographic Framework, "
881 	    "OU=Partner Object Signing, "
882 	    "O=Sun Microsystems Inc";
883 	const char	 SunCDNFMT[] =
884 	    "CN=%s, "
885 	    "OU=Class B, "
886 	    "OU=Solaris Cryptographic Framework, "
887 	    "OU=Corporate Object Signing, "
888 	    "O=Sun Microsystems Inc";
889 	const char	 SunSDNFMT[] =
890 	    "CN=%s, "
891 	    "OU=Class B, "
892 	    "OU=Solaris Signed Execution, "
893 	    "OU=Corporate Object Signing, "
894 	    "O=Sun Microsystems Inc";
895 	const char	 *dnfmt = NULL;
896 	char	cn[CN_MAX_LENGTH + 1];
897 	char	*dn = NULL;
898 	size_t	dn_len;
899 	KMF_RETURN   kmfret;
900 	cryptodebug("do_cert_request");
901 
902 	/*
903 	 * Get the DN prefix from the user
904 	 */
905 	switch (cmd_info.internal_req) {
906 	case 'c':
907 		dnfmt = SunCDNFMT;
908 		(void) fprintf(stdout, gettext(
909 		    "Enter Sun Microsystems, Inc. Release name.\n"
910 		    "This will be the prefix of the Certificate DN: "));
911 		break;
912 	case 's':
913 		dnfmt = SunSDNFMT;
914 		(void) fprintf(stdout, gettext(
915 		    "Enter Sun Microsystems, Inc. Release name.\n"
916 		    "This will be the prefix of the Certificate DN: "));
917 		break;
918 	default:
919 		dnfmt = PartnerDNFMT;
920 		(void) fprintf(stdout, gettext(
921 		    "Enter Company Name / Stock Symbol"
922 		    " or some other globally unique identifier.\n"
923 		    "This will be the prefix of the Certificate DN: "));
924 		break;
925 	}
926 
927 	(void) fgets(cn, sizeof (cn), stdin);
928 	if ((cn == NULL) || (cn[0] == '\n')) {
929 		es_error(gettext("you must specify a Certificate DN prefix"));
930 		return (EXIT_INVALID_ARG);
931 	}
932 
933 	if (cn[strlen(cn) - 1] == '\n') {
934 		cn[strlen(cn) - 1] = '\0';	/* chop trailing \n */
935 	} else {
936 		es_error(gettext("You must specify a Certificate DN prefix "
937 		    "of no more than %d characters"), CN_MAX_LENGTH);
938 		return (EXIT_INVALID_ARG);
939 	}
940 
941 	/* Update DN string */
942 	dn_len = strlen(cn) + strlen(dnfmt);
943 	dn = malloc(dn_len + 1);
944 	(void) snprintf(dn, dn_len, dnfmt, cn);
945 
946 	cryptodebug("Generating Certificate request for DN: %s", dn);
947 	kmfret = create_csr(dn);
948 	free(dn);
949 	if (kmfret == KMF_OK)
950 		return (EXIT_OKAY);
951 	else
952 		return (EXIT_CSR_FAILED);
953 }
954 
955 static void
956 str_print(char *s)
957 {
958 	if (s == NULL)
959 		return;
960 	(void) fprintf(stdout, "%s\n", s);
961 }
962 
963 /*ARGSUSED*/
964 static ret_t
965 do_list(char *object)
966 {
967 	ret_t	retval;
968 
969 	if (cmd_info.elfcnt > 0) {
970 		ELFsign_status_t	elfstat;
971 		struct filesignatures	*fssp = NULL;
972 		size_t fs_len;
973 		struct ELFsign_sig_info	*esip;
974 
975 		if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
976 			return (retval);
977 		elfstat = elfsign_signatures(cmd_info.ess,
978 		    &fssp, &fs_len, ES_GET);
979 		if (elfstat == ELFSIGN_SUCCESS) {
980 			retval = EXIT_OKAY;
981 			if (elfsign_sig_info(fssp, &esip)) {
982 				switch (cmd_info.field) {
983 				case FLD_FORMAT:
984 					str_print(esip->esi_format);
985 					break;
986 				case FLD_SIGNER:
987 					str_print(esip->esi_signer);
988 					break;
989 				case FLD_TIME:
990 					if (esip->esi_time == 0)
991 						retval = EXIT_INVALID_ARG;
992 					else
993 						str_print(time_str(
994 						    esip->esi_time));
995 					break;
996 				default:
997 					retval = EXIT_INVALID_ARG;
998 				}
999 				elfsign_sig_info_free(esip);
1000 			}
1001 			free(fssp);
1002 		} else
1003 			retval = EXIT_VERIFY_FAILED_UNSIGNED;
1004 		elfsign_end(cmd_info.ess);
1005 	} else {
1006 		ELFCert_t	cert;
1007 		/*
1008 		 * Initialize the ESS record here even though we are not
1009 		 * actually opening any ELF files.
1010 		 */
1011 		if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
1012 		    ELFSIGN_SUCCESS)
1013 			return (EXIT_MEMORY_ERROR);
1014 
1015 		if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
1016 		    &cert, cmd_info.es_action)) {
1017 			retval = EXIT_OKAY;
1018 			switch (cmd_info.field) {
1019 			case FLD_SUBJECT:
1020 				str_print(elfcertlib_getdn(cert));
1021 				break;
1022 			case FLD_ISSUER:
1023 				str_print(elfcertlib_getissuer(cert));
1024 				break;
1025 			default:
1026 				retval = EXIT_INVALID_ARG;
1027 			}
1028 			elfcertlib_releasecert(cmd_info.ess, cert);
1029 		} else
1030 			retval = EXIT_BAD_CERT;
1031 		elfsign_end(cmd_info.ess);
1032 	}
1033 
1034 	return (retval);
1035 }
1036 
1037 static void
1038 es_error(const char *fmt, ...)
1039 {
1040 	char msgbuf[BUFSIZ];
1041 	va_list	args;
1042 
1043 	va_start(args, fmt);
1044 	(void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
1045 	va_end(args);
1046 	(void) fflush(stdout);
1047 	cryptoerror(LOG_STDERR, "%s", msgbuf);
1048 	(void) fflush(stderr);
1049 }
1050 
1051 static char *
1052 time_str(time_t t)
1053 {
1054 	static char	buf[80];
1055 	char		*bufp;
1056 
1057 	bufp = buf;
1058 	if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
1059 		bufp = ctime(&t);
1060 	return (bufp);
1061 }
1062 
1063 static void
1064 sig_info_print(struct ELFsign_sig_info *esip)
1065 {
1066 	if (esip == NULL)
1067 		return;
1068 	(void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
1069 	(void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
1070 	if (esip->esi_time == 0)
1071 		return;
1072 	(void) fprintf(stdout, gettext("signed on: %s.\n"),
1073 	    time_str(esip->esi_time));
1074 }
1075