dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-crypto / elfsign / elfsign.c
blob1948f779762ec8a2cc2b9dcd2d66ec0c96280f10
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Developer command for adding the signature section to an ELF object
28 * PSARC 2001/488
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
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>
49 #include <cryptoutil.h>
50 #include <sys/crypto/elfsign.h>
51 #include <libelfsign.h>
53 #include <kmfapi.h>
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:"
64 enum cmd_e {
65 ES_SIGN,
66 ES_VERIFY,
67 ES_REQUEST,
68 ES_LIST
71 enum field_e {
72 FLD_UNKNOWN,
73 FLD_SUBJECT,
74 FLD_ISSUER,
75 FLD_FORMAT,
76 FLD_SIGNER,
77 FLD_TIME
80 #define MIN_ARGS 3 /* The minimum # args to do anything */
81 #define ES_DEFAULT_KEYSIZE 1024
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;
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
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
125 typedef enum ret_e ret_t;
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);
139 main(int argc, char **argv)
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;
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);
155 cryptodebug_init("elfsign");
157 if (argc < MIN_ARGS) {
158 es_error(gettext("invalid number of arguments"));
159 usage();
160 return (EXIT_INVALID_ARG);
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;
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);
206 * Note: There is no need to check that optarg isn't NULL
207 * because getopt does that for us.
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);
215 switch (c) {
216 case 'c':
217 cmd_info.cert = optarg;
218 break;
219 case 'e':
220 cmd_info.elfcnt++;
221 cmd_info.elfobj = reallocarray(cmd_info.elfobj,
222 cmd_info.elfcnt, sizeof (char *));
223 if (cmd_info.elfobj == NULL) {
224 es_error(gettext(
225 "Too many elf objects specified."));
226 return (EXIT_INVALID_ARG);
228 cmd_info.elfobj[cmd_info.elfcnt - 1] = optarg;
229 break;
230 case 'f':
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;
240 if (cmd_info.field == FLD_UNKNOWN) {
241 cryptodebug("Invalid field option");
242 errflag++;
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++;
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++;
286 optind++; /* we skipped over subcommand */
287 cmd_info.extracnt = argc - optind;
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++;
296 switch (cmd_info.cmd) {
297 case ES_VERIFY:
298 if (cmd_info.elfcnt + argc - optind == 0) {
299 cryptodebug("Missing elfobj");
300 errflag++;
302 break;
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++;
312 break;
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++;
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++;
327 break;
330 if (errflag) {
331 usage();
332 return (EXIT_INVALID_ARG);
335 switch (cmd_info.cmd) {
336 case ES_REQUEST:
337 case ES_LIST:
338 ret = action(NULL);
339 break;
340 default:
342 int i;
343 ret_t iret;
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;
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;
359 break;
363 free(cmd_info.elfobj);
365 return (ret);
369 static void
370 usage(void)
372 /* BEGIN CSTYLED */
373 (void) fprintf(stderr, gettext(
374 "usage:\n"
375 "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n"
376 "\t\t[-F <format>] -k <private_key_file> [elf_object]..."
377 "\n"
378 "\telfsign sign [-v] [-e <elf_object>] -c <certificate_file>\n"
379 "\t\t[-F <format>] -T <token_label> [-P <pin_file>] [elf_object]..."
380 "\n\n"
381 "\telfsign verify [-v] [-c <certificate_file>] [-e <elf_object>]\n"
382 "\t\t[elf_object]..."
383 "\n\n"
384 "\telfsign request -r <certificate_request_file> -k <private_key_file>"
385 "\n"
386 "\telfsign request -r <certificate_request_file> -T <token_label>"
387 "\n\n"
388 "\telfsign list -f field -c <certificate_file>"
389 "\n"
390 "\telfsign list -f field -e <elf_object>"
391 "\n"));
392 /* END CSTYLED */
395 static ret_t
396 getelfobj(char *elfpath)
398 ELFsign_status_t estatus;
399 ret_t ret = EXIT_SIGN_FAILED;
401 estatus = elfsign_begin(elfpath, cmd_info.es_action, &(cmd_info.ess));
402 switch (estatus) {
403 case ELFSIGN_SUCCESS:
404 ret = EXIT_OKAY;
405 break;
406 case ELFSIGN_INVALID_ELFOBJ:
407 es_error(gettext(
408 "Unable to open %s as an ELF object."),
409 elfpath);
410 ret = EXIT_CANT_OPEN_ELF_OBJECT;
411 break;
412 default:
413 es_error(gettext("unexpected failure: %d"), estatus);
414 if (cmd_info.cmd == ES_SIGN) {
415 ret = EXIT_SIGN_FAILED;
416 } else if (cmd_info.cmd == ES_VERIFY) {
417 ret = EXIT_VERIFY_FAILED;
421 return (ret);
424 static ret_t
425 setcertpath(void)
427 ELFsign_status_t estatus;
428 ret_t ret = EXIT_SIGN_FAILED;
430 if (cmd_info.cert == NULL)
431 return (EXIT_OKAY);
432 estatus = elfsign_setcertpath(cmd_info.ess, cmd_info.cert);
433 switch (estatus) {
434 case ELFSIGN_SUCCESS:
435 ret = EXIT_OKAY;
436 break;
437 case ELFSIGN_INVALID_CERTPATH:
438 if (cmd_info.cert != NULL) {
439 es_error(gettext("Unable to open %s as a certificate."),
440 cmd_info.cert);
442 ret = EXIT_BAD_CERT;
443 break;
444 default:
445 es_error(gettext("unusable certificate: %s"), cmd_info.cert);
446 if (cmd_info.cmd == ES_SIGN) {
447 ret = EXIT_SIGN_FAILED;
448 } else if (cmd_info.cmd == ES_VERIFY) {
449 ret = EXIT_VERIFY_FAILED;
453 return (ret);
457 * getpin - return pointer to token PIN in static storage
459 static char *
460 getpin(void)
462 static char pinbuf[PASS_MAX + 1];
463 char *pp;
464 FILE *pinfile;
466 if (cmd_info.pinpath == NULL)
467 return (getpassphrase(
468 gettext("Enter PIN for PKCS#11 token: ")));
469 if ((pinfile = fopen(cmd_info.pinpath, "r")) == NULL) {
470 es_error(gettext("failed to open %s."),
471 cmd_info.pinpath);
472 return (NULL);
475 pp = fgets(pinbuf, sizeof (pinbuf), pinfile);
476 (void) fclose(pinfile);
477 if (pp == NULL) {
478 es_error(gettext("failed to read PIN from %s."),
479 cmd_info.pinpath);
480 return (NULL);
482 pp = &pinbuf[strlen(pinbuf) - 1];
483 if (*pp == '\n')
484 *pp = '\0';
485 return (pinbuf);
489 * Add the .SUNW_signature sections for the ELF signature
491 static ret_t
492 do_sign(char *object)
494 ret_t ret;
495 ELFsign_status_t elfstat;
496 struct filesignatures *fssp = NULL;
497 size_t fs_len;
498 uchar_t sig[SIG_MAX_LENGTH];
499 size_t sig_len = SIG_MAX_LENGTH;
500 uchar_t hash[SIG_MAX_LENGTH];
501 size_t hash_len = SIG_MAX_LENGTH;
502 ELFCert_t cert = NULL;
503 char *dn;
504 size_t dn_len;
506 cryptodebug("do_sign");
507 if ((ret = getelfobj(object)) != EXIT_OKAY)
508 return (ret);
510 if (cmd_info.token_label &&
511 !elfcertlib_settoken(cmd_info.ess, cmd_info.token_label)) {
512 es_error(gettext("Unable to access token: %s"),
513 cmd_info.token_label);
514 ret = EXIT_SIGN_FAILED;
515 goto cleanup;
518 if ((ret = setcertpath()) != EXIT_OKAY)
519 goto cleanup;
521 if (!elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL, &cert,
522 cmd_info.es_action)) {
523 es_error(gettext("Unable to load certificate: %s"),
524 cmd_info.cert);
525 ret = EXIT_BAD_CERT;
526 goto cleanup;
529 if (cmd_info.privpath != NULL) {
530 if (!elfcertlib_loadprivatekey(cmd_info.ess, cert,
531 cmd_info.privpath)) {
532 es_error(gettext("Unable to load private key: %s"),
533 cmd_info.privpath);
534 ret = EXIT_BAD_PRIVATEKEY;
535 goto cleanup;
537 } else {
538 char *pin = getpin();
539 if (pin == NULL) {
540 es_error(gettext("Unable to get PIN"));
541 ret = EXIT_BAD_PRIVATEKEY;
542 goto cleanup;
544 if (!elfcertlib_loadtokenkey(cmd_info.ess, cert,
545 cmd_info.token_label, pin)) {
546 es_error(gettext("Unable to access private key "
547 "in token %s"), cmd_info.token_label);
548 ret = EXIT_BAD_PRIVATEKEY;
549 goto cleanup;
554 * Get the DN from the certificate.
556 if ((dn = elfcertlib_getdn(cert)) == NULL) {
557 es_error(gettext("Unable to find DN in certificate %s"),
558 cmd_info.cert);
559 ret = EXIT_SIGN_FAILED;
560 goto cleanup;
562 dn_len = strlen(dn);
563 cryptodebug("DN = %s", dn);
565 elfstat = elfsign_signatures(cmd_info.ess, &fssp, &fs_len, ES_GET);
566 if (elfstat != ELFSIGN_SUCCESS) {
567 if (elfstat != ELFSIGN_NOTSIGNED) {
568 es_error(gettext("Unable to retrieve existing "
569 "signature block in %s"), object);
570 ret = EXIT_SIGN_FAILED;
571 goto cleanup;
573 fssp = NULL;
575 * force creation and naming of signature section
576 * so the hash doesn't change
578 if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
579 cmd_info.es_action) != ELFSIGN_SUCCESS) {
580 es_error(gettext("Unable to insert "
581 "signature block into %s"), object);
582 ret = EXIT_SIGN_FAILED;
583 goto cleanup;
587 bzero(hash, sizeof (hash));
588 if (elfsign_hash(cmd_info.ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
589 es_error(gettext("Unable to calculate hash of ELF object %s"),
590 object);
591 ret = EXIT_SIGN_FAILED;
592 goto cleanup;
595 bzero(sig, sizeof (sig));
596 if (!elfcertlib_sign(cmd_info.ess, cert,
597 hash, hash_len, sig, &sig_len)) {
598 es_error(gettext("Unable to sign %s using key from %s"),
599 object, cmd_info.privpath ?
600 cmd_info.privpath : cmd_info.token_label);
601 ret = EXIT_SIGN_FAILED;
602 goto cleanup;
605 { /* DEBUG START */
606 const int sigstr_len = sizeof (char) * sig_len * 2 + 1;
607 char *sigstr = malloc(sigstr_len);
609 tohexstr(sig, sig_len, sigstr, sigstr_len);
610 cryptodebug("sig value is: %s", sigstr);
611 free(sigstr);
612 } /* DEBUG END */
614 fssp = elfsign_insert_dso(cmd_info.ess, fssp,
615 dn, dn_len, sig, sig_len, NULL, 0);
616 if (fssp == NULL) {
617 es_error(gettext("Unable to prepare signature for %s"),
618 object);
619 ret = EXIT_SIGN_FAILED;
620 goto cleanup;
622 if (elfsign_signatures(cmd_info.ess, &fssp, &fs_len,
623 cmd_info.es_action) != ELFSIGN_SUCCESS) {
624 es_error(gettext("Unable to update %s: with signature"),
625 object);
626 ret = EXIT_SIGN_FAILED;
627 goto cleanup;
629 if (cmd_info.verbose || (cmd_info.elfcnt + cmd_info.extracnt) > 1) {
630 (void) fprintf(stdout,
631 gettext("elfsign: %s signed successfully.\n"),
632 object);
634 if (cmd_info.verbose) {
635 struct ELFsign_sig_info *esip;
637 if (elfsign_sig_info(fssp, &esip)) {
638 sig_info_print(esip);
639 elfsign_sig_info_free(esip);
643 ret = EXIT_OKAY;
645 cleanup:
646 free(fssp);
647 bzero(sig, sig_len);
648 bzero(hash, hash_len);
650 if (cert != NULL)
651 elfcertlib_releasecert(cmd_info.ess, cert);
652 if (cmd_info.ess != NULL)
653 elfsign_end(cmd_info.ess);
655 return (ret);
659 * Verify the signature of the object
660 * This subcommand is intended to be used by developers during their build
661 * processes. Therefore we can not assume that the certificate is in
662 * /etc/crypto/certs so we must use the path we got from the commandline.
664 static ret_t
665 do_verify(char *object)
667 ELFsign_status_t res;
668 struct ELFsign_sig_info *esip;
669 ret_t retval;
671 cryptodebug("do_verify");
672 if ((retval = getelfobj(object)) != EXIT_OKAY)
673 return (retval);
675 if ((retval = setcertpath()) != EXIT_OKAY) {
676 elfsign_end(cmd_info.ess);
677 return (retval);
680 res = elfsign_verify_signature(cmd_info.ess, &esip);
681 switch (res) {
682 case ELFSIGN_SUCCESS:
683 (void) fprintf(stdout,
684 gettext("elfsign: verification of %s passed.\n"),
685 object);
686 if (cmd_info.verbose)
687 sig_info_print(esip);
688 retval = EXIT_OKAY;
689 break;
690 case ELFSIGN_FAILED:
691 case ELFSIGN_INVALID_CERTPATH:
692 es_error(gettext("verification of %s failed."),
693 object);
694 if (cmd_info.verbose)
695 sig_info_print(esip);
696 retval = EXIT_VERIFY_FAILED;
697 break;
698 case ELFSIGN_NOTSIGNED:
699 es_error(gettext("no signature found in %s."),
700 object);
701 retval = EXIT_VERIFY_FAILED_UNSIGNED;
702 break;
703 default:
704 es_error(gettext("unexpected failure attempting verification "
705 "of %s."), object);
706 retval = EXIT_VERIFY_FAILED_UNSIGNED;
707 break;
710 if (esip != NULL)
711 elfsign_sig_info_free(esip);
712 if (cmd_info.ess != NULL)
713 elfsign_end(cmd_info.ess);
714 return (retval);
717 #define SET_VALUE(f, s) \
718 kmfrv = f; \
719 if (kmfrv != KMF_OK) { \
720 char *e = NULL; \
721 (void) kmf_get_kmf_error_str(kmfrv, &e); \
722 cryptoerror(LOG_STDERR, \
723 gettext("Failed to %s: %s\n"), \
724 s, (e ? e : "unknown error")); \
725 if (e) free(e); \
726 goto cleanup; \
729 static KMF_RETURN
730 create_csr(char *dn)
732 KMF_RETURN kmfrv = KMF_OK;
733 KMF_HANDLE_T kmfhandle = NULL;
734 KMF_KEY_HANDLE pubk, prik;
735 KMF_X509_NAME csrSubject;
736 KMF_CSR_DATA csr;
737 KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_MD5WithRSA;
738 KMF_DATA signedCsr = { 0, NULL };
739 char *err;
740 KMF_ATTRIBUTE attrlist[16];
741 KMF_ENCODE_FORMAT format;
742 KMF_KEYSTORE_TYPE kstype;
743 KMF_KEY_ALG keytype;
744 uint32_t keylength;
745 KMF_CREDENTIAL cred;
746 char *pin = NULL;
747 int numattr;
749 if ((kmfrv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
750 (void) kmf_get_kmf_error_str(kmfrv, &err);
751 cryptoerror(LOG_STDERR,
752 gettext("Error initializing KMF: %s\n"),
753 (err ? err : "unknown error"));
754 free(err);
755 return (kmfrv);
757 (void) memset(&csr, 0, sizeof (csr));
758 (void) memset(&csrSubject, 0, sizeof (csrSubject));
760 if (cmd_info.privpath != NULL) {
761 kstype = KMF_KEYSTORE_OPENSSL;
762 format = KMF_FORMAT_ASN1;
763 } else {
764 boolean_t readonly;
765 /* args checking verified (cmd_info.token_label != NULL) */
767 /* Get a PIN to store the private key in the token */
768 pin = getpin();
770 if (pin == NULL) {
771 (void) kmf_finalize(kmfhandle);
772 return (KMF_ERR_AUTH_FAILED);
775 kstype = KMF_KEYSTORE_PK11TOKEN;
776 readonly = B_FALSE;
778 numattr = 0;
779 kmf_set_attr_at_index(attrlist, numattr++,
780 KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
781 kmf_set_attr_at_index(attrlist, numattr++,
782 KMF_TOKEN_LABEL_ATTR, cmd_info.token_label,
783 strlen(cmd_info.token_label));
784 kmf_set_attr_at_index(attrlist, numattr++,
785 KMF_READONLY_ATTR, &readonly, sizeof (readonly));
786 kmfrv = kmf_configure_keystore(kmfhandle, numattr, attrlist);
787 if (kmfrv != KMF_OK) {
788 goto cleanup;
792 /* Create the RSA keypair */
793 keytype = KMF_RSA;
794 keylength = ES_DEFAULT_KEYSIZE;
795 (void) memset(&prik, 0, sizeof (prik));
796 (void) memset(&pubk, 0, sizeof (pubk));
798 numattr = 0;
799 kmf_set_attr_at_index(attrlist, numattr++,
800 KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
801 kmf_set_attr_at_index(attrlist, numattr++,
802 KMF_KEYALG_ATTR, &keytype, sizeof (keytype));
803 kmf_set_attr_at_index(attrlist, numattr++,
804 KMF_KEYLENGTH_ATTR, &keylength, sizeof (keylength));
805 if (pin != NULL) {
806 cred.cred = pin;
807 cred.credlen = strlen(pin);
808 kmf_set_attr_at_index(attrlist, numattr++,
809 KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL));
811 kmf_set_attr_at_index(attrlist, numattr++,
812 KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE));
813 kmf_set_attr_at_index(attrlist, numattr++,
814 KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (KMF_KEY_HANDLE));
815 if (kstype == KMF_KEYSTORE_OPENSSL) {
816 kmf_set_attr_at_index(attrlist, numattr++,
817 KMF_KEY_FILENAME_ATTR, cmd_info.privpath,
818 strlen(cmd_info.privpath));
819 kmf_set_attr_at_index(attrlist, numattr++,
820 KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format));
823 kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
824 if (kmfrv != KMF_OK) {
825 (void) kmf_get_kmf_error_str(kmfrv, &err);
826 cryptoerror(LOG_STDERR,
827 gettext("Create RSA keypair failed: %s"),
828 (err ? err : "unknown error"));
829 free(err);
830 goto cleanup;
833 kmfrv = kmf_dn_parser(dn, &csrSubject);
834 if (kmfrv != KMF_OK) {
835 (void) kmf_get_kmf_error_str(kmfrv, &err);
836 cryptoerror(LOG_STDERR,
837 gettext("Error parsing subject name: %s\n"),
838 (err ? err : "unknown error"));
839 free(err);
840 goto cleanup;
843 SET_VALUE(kmf_set_csr_pubkey(kmfhandle, &pubk, &csr), "keypair");
845 SET_VALUE(kmf_set_csr_version(&csr, 2), "version number");
847 SET_VALUE(kmf_set_csr_subject(&csr, &csrSubject), "subject name");
849 SET_VALUE(kmf_set_csr_sig_alg(&csr, sigAlg), "SignatureAlgorithm");
851 if ((kmfrv = kmf_sign_csr(kmfhandle, &csr, &prik, &signedCsr)) ==
852 KMF_OK) {
853 kmfrv = kmf_create_csr_file(&signedCsr, KMF_FORMAT_PEM,
854 cmd_info.cert);
857 cleanup:
858 (void) kmf_free_kmf_key(kmfhandle, &prik);
859 (void) kmf_free_data(&signedCsr);
860 (void) kmf_free_signed_csr(&csr);
861 (void) kmf_finalize(kmfhandle);
863 return (kmfrv);
867 #define CN_MAX_LENGTH 64 /* Verisign implementation limit */
869 * Generate a certificate request into the file named cmd_info.cert
871 /*ARGSUSED*/
872 static ret_t
873 do_cert_request(char *object)
875 const char PartnerDNFMT[] =
876 "CN=%s, "
877 "OU=Class B, "
878 "OU=Solaris Cryptographic Framework, "
879 "OU=Partner Object Signing, "
880 "O=Sun Microsystems Inc";
881 const char SunCDNFMT[] =
882 "CN=%s, "
883 "OU=Class B, "
884 "OU=Solaris Cryptographic Framework, "
885 "OU=Corporate Object Signing, "
886 "O=Sun Microsystems Inc";
887 const char SunSDNFMT[] =
888 "CN=%s, "
889 "OU=Class B, "
890 "OU=Solaris Signed Execution, "
891 "OU=Corporate Object Signing, "
892 "O=Sun Microsystems Inc";
893 const char *dnfmt = NULL;
894 char cn[CN_MAX_LENGTH + 1];
895 char *dn = NULL;
896 size_t dn_len;
897 KMF_RETURN kmfret;
898 cryptodebug("do_cert_request");
901 * Get the DN prefix from the user
903 switch (cmd_info.internal_req) {
904 case 'c':
905 dnfmt = SunCDNFMT;
906 (void) fprintf(stdout, gettext(
907 "Enter Sun Microsystems, Inc. Release name.\n"
908 "This will be the prefix of the Certificate DN: "));
909 break;
910 case 's':
911 dnfmt = SunSDNFMT;
912 (void) fprintf(stdout, gettext(
913 "Enter Sun Microsystems, Inc. Release name.\n"
914 "This will be the prefix of the Certificate DN: "));
915 break;
916 default:
917 dnfmt = PartnerDNFMT;
918 (void) fprintf(stdout, gettext(
919 "Enter Company Name / Stock Symbol"
920 " or some other globally unique identifier.\n"
921 "This will be the prefix of the Certificate DN: "));
922 break;
924 if ((fgets(cn, sizeof (cn), stdin) == NULL) || (cn[0] == '\n')) {
925 es_error(gettext("you must specify a Certificate DN prefix"));
926 return (EXIT_INVALID_ARG);
929 if (cn[strlen(cn) - 1] == '\n') {
930 cn[strlen(cn) - 1] = '\0'; /* chop trailing \n */
931 } else {
932 es_error(gettext("You must specify a Certificate DN prefix "
933 "of no more than %d characters"), CN_MAX_LENGTH);
934 return (EXIT_INVALID_ARG);
937 /* Update DN string */
938 dn_len = strlen(cn) + strlen(dnfmt);
939 dn = malloc(dn_len + 1);
940 (void) snprintf(dn, dn_len, dnfmt, cn);
942 cryptodebug("Generating Certificate request for DN: %s", dn);
943 kmfret = create_csr(dn);
944 free(dn);
945 if (kmfret == KMF_OK)
946 return (EXIT_OKAY);
947 else
948 return (EXIT_CSR_FAILED);
951 static void
952 str_print(char *s)
954 if (s == NULL)
955 return;
956 (void) fprintf(stdout, "%s\n", s);
959 /*ARGSUSED*/
960 static ret_t
961 do_list(char *object)
963 ret_t retval;
965 if (cmd_info.elfcnt > 0) {
966 ELFsign_status_t elfstat;
967 struct filesignatures *fssp = NULL;
968 size_t fs_len;
969 struct ELFsign_sig_info *esip;
971 if ((retval = getelfobj(cmd_info.elfobj[0])) != EXIT_OKAY)
972 return (retval);
973 elfstat = elfsign_signatures(cmd_info.ess,
974 &fssp, &fs_len, ES_GET);
975 if (elfstat == ELFSIGN_SUCCESS) {
976 retval = EXIT_OKAY;
977 if (elfsign_sig_info(fssp, &esip)) {
978 switch (cmd_info.field) {
979 case FLD_FORMAT:
980 str_print(esip->esi_format);
981 break;
982 case FLD_SIGNER:
983 str_print(esip->esi_signer);
984 break;
985 case FLD_TIME:
986 if (esip->esi_time == 0)
987 retval = EXIT_INVALID_ARG;
988 else
989 str_print(time_str(
990 esip->esi_time));
991 break;
992 default:
993 retval = EXIT_INVALID_ARG;
995 elfsign_sig_info_free(esip);
997 free(fssp);
998 } else
999 retval = EXIT_VERIFY_FAILED_UNSIGNED;
1000 elfsign_end(cmd_info.ess);
1001 } else {
1002 ELFCert_t cert;
1004 * Initialize the ESS record here even though we are not
1005 * actually opening any ELF files.
1007 if (elfsign_begin(NULL, ES_GET, &(cmd_info.ess)) !=
1008 ELFSIGN_SUCCESS)
1009 return (EXIT_MEMORY_ERROR);
1011 if (elfcertlib_getcert(cmd_info.ess, cmd_info.cert, NULL,
1012 &cert, cmd_info.es_action)) {
1013 retval = EXIT_OKAY;
1014 switch (cmd_info.field) {
1015 case FLD_SUBJECT:
1016 str_print(elfcertlib_getdn(cert));
1017 break;
1018 case FLD_ISSUER:
1019 str_print(elfcertlib_getissuer(cert));
1020 break;
1021 default:
1022 retval = EXIT_INVALID_ARG;
1024 elfcertlib_releasecert(cmd_info.ess, cert);
1025 } else
1026 retval = EXIT_BAD_CERT;
1027 elfsign_end(cmd_info.ess);
1030 return (retval);
1033 static void
1034 es_error(const char *fmt, ...)
1036 char msgbuf[BUFSIZ];
1037 va_list args;
1039 va_start(args, fmt);
1040 (void) vsnprintf(msgbuf, sizeof (msgbuf), fmt, args);
1041 va_end(args);
1042 (void) fflush(stdout);
1043 cryptoerror(LOG_STDERR, "%s", msgbuf);
1044 (void) fflush(stderr);
1047 static char *
1048 time_str(time_t t)
1050 static char buf[80];
1051 char *bufp;
1053 bufp = buf;
1054 if (strftime(buf, sizeof (buf), NULL, localtime(&t)) == 0)
1055 bufp = ctime(&t);
1056 return (bufp);
1059 static void
1060 sig_info_print(struct ELFsign_sig_info *esip)
1062 if (esip == NULL)
1063 return;
1064 (void) fprintf(stdout, gettext("format: %s.\n"), esip->esi_format);
1065 (void) fprintf(stdout, gettext("signer: %s.\n"), esip->esi_signer);
1066 if (esip->esi_time == 0)
1067 return;
1068 (void) fprintf(stdout, gettext("signed on: %s.\n"),
1069 time_str(esip->esi_time));