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