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
main(int argc,char ** argv)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 int 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
usage(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
getelfobj(char * elfpath)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
setcertpath(void)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 *
getpin(void)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
do_sign(char * object)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
do_verify(char * object)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
create_csr(char * dn)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 = { 0, NULL };
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
do_cert_request(char * object)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 if ((fgets(cn, sizeof (cn), stdin) == NULL) || (cn[0] == '\n')) {
927 es_error(gettext("you must specify a Certificate DN prefix"));
928 return (EXIT_INVALID_ARG);
929 }
930
931 if (cn[strlen(cn) - 1] == '\n') {
932 cn[strlen(cn) - 1] = '\0'; /* chop trailing \n */
933 } else {
934 es_error(gettext("You must specify a Certificate DN prefix "
935 "of no more than %d characters"), CN_MAX_LENGTH);
936 return (EXIT_INVALID_ARG);
937 }
938
939 /* Update DN string */
940 dn_len = strlen(cn) + strlen(dnfmt);
941 dn = malloc(dn_len + 1);
942 (void) snprintf(dn, dn_len, dnfmt, cn);
943
944 cryptodebug("Generating Certificate request for DN: %s", dn);
945 kmfret = create_csr(dn);
946 free(dn);
947 if (kmfret == KMF_OK)
948 return (EXIT_OKAY);
949 else
950 return (EXIT_CSR_FAILED);
951 }
952
953 static void
str_print(char * s)954 str_print(char *s)
955 {
956 if (s == NULL)
957 return;
958 (void) fprintf(stdout, "%s\n", s);
959 }
960
961 /*ARGSUSED*/
962 static ret_t
do_list(char * object)963 do_list(char *object)
964 {
965 ret_t retval;
966
967 if (cmd_info.elfcnt > 0) {
968 ELFsign_status_t elfstat;
969 struct filesignatures *fssp = NULL;
970 size_t fs_len;
971 struct ELFsign_sig_info *esip;
972
973 if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
974 return (retval);
975 elfstat = elfsign_signatures(cmd_info.ess,
976 &fssp, &fs_len, ES_GET);
977 if (elfstat == ELFSIGN_SUCCESS) {
978 retval = EXIT_OKAY;
979 if (elfsign_sig_info(fssp, &esip)) {
980 switch (cmd_info.field) {
981 case FLD_FORMAT:
982 str_print(esip->esi_format);
983 break;
984 case FLD_SIGNER:
985 str_print(esip->esi_signer);
986 break;
987 case FLD_TIME:
988 if (esip->esi_time == 0)
989 retval = EXIT_INVALID_ARG;
990 else
991 str_print(time_str(
992 esip->esi_time));
993 break;
994 default:
995 retval = EXIT_INVALID_ARG;
996 }
997 elfsign_sig_info_free(esip);
998 }
999 free(fssp);
1000 } else
1001 retval = EXIT_VERIFY_FAILED_UNSIGNED;
1002 elfsign_end(cmd_info.ess);
1003 } else {
1004 ELFCert_t cert;
1005 /*
1006 * Initialize the ESS record here even though we are not
1007 * actually opening any ELF files.
1008 */
1009 if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
1010 ELFSIGN_SUCCESS)
1011 return (EXIT_MEMORY_ERROR);
1012
1013 if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
1014 &cert, cmd_info.es_action)) {
1015 retval = EXIT_OKAY;
1016 switch (cmd_info.field) {
1017 case FLD_SUBJECT:
1018 str_print(elfcertlib_getdn(cert));
1019 break;
1020 case FLD_ISSUER:
1021 str_print(elfcertlib_getissuer(cert));
1022 break;
1023 default:
1024 retval = EXIT_INVALID_ARG;
1025 }
1026 elfcertlib_releasecert(cmd_info.ess, cert);
1027 } else
1028 retval = EXIT_BAD_CERT;
1029 elfsign_end(cmd_info.ess);
1030 }
1031
1032 return (retval);
1033 }
1034
1035 static void
es_error(const char * fmt,...)1036 es_error(const char *fmt, ...)
1037 {
1038 char msgbuf[BUFSIZ];
1039 va_list args;
1040
1041 va_start(args, fmt);
1042 (void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
1043 va_end(args);
1044 (void) fflush(stdout);
1045 cryptoerror(LOG_STDERR, "%s", msgbuf);
1046 (void) fflush(stderr);
1047 }
1048
1049 static char *
time_str(time_t t)1050 time_str(time_t t)
1051 {
1052 static char buf[80];
1053 char *bufp;
1054
1055 bufp = buf;
1056 if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
1057 bufp = ctime(&t);
1058 return (bufp);
1059 }
1060
1061 static void
sig_info_print(struct ELFsign_sig_info * esip)1062 sig_info_print(struct ELFsign_sig_info *esip)
1063 {
1064 if (esip == NULL)
1065 return;
1066 (void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
1067 (void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
1068 if (esip->esi_time == 0)
1069 return;
1070 (void) fprintf(stdout, gettext("signed on: %s.\n"),
1071 time_str(esip->esi_time));
1072 }
1073