Beispiel #1
0
int
main(int argc, char *argv[])
{
	int rc;

	pesign_context ctx, *ctxp = &ctx;

	int list = 0;
	int remove = 0;

	char *digest_name = "sha256";

	poptContext optCon;
	struct poptOption options[] = {
		{NULL, '\0', POPT_ARG_INTL_DOMAIN, "pesign" },
		{"in", 'i', POPT_ARG_STRING, &ctx.infile, 0,
			"specify input file", "<infile>"},
		{"out", 'o', POPT_ARG_STRING, &ctx.outfile, 0,
			"specify output file", "<outfile>" },
		{"certficate", 'c', POPT_ARG_STRING, &ctx.cms_ctx.certname, 0,
			"specify certificate nickname",
			"<certificate nickname>" },
		{"privkey", 'p', POPT_ARG_STRING, &ctx.privkeyfile, 0,
			"specify private key file", "<privkey>" },
		{"force", 'f', POPT_ARG_VAL, &ctx.force,  1,
			"force overwriting of output file", NULL },
		{"nogaps", 'n',
			POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,
			&ctx.hashgaps, 0,
			"skip gaps between sections when signing", NULL },
		{"sign", 's', POPT_ARG_VAL, &ctx.sign, 1,
			"create a new signature", NULL },
		{"hash", 'h', POPT_ARG_VAL, &ctx.hash, 1, "hash binary", NULL },
		{"digest_type", 'd', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
			&digest_name, 0, "digest type to use for pe hash" },
		{"import-signature", 'm',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctx.insig, 0,"import signature from file", "<insig>" },
		{"signature-number", 'u', POPT_ARG_INT, &ctx.signum, -1,
			"specify which signature to operate on","<sig-number>"},
		{"list-signatures", 'l',
			POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,
			&list, 1, "list signatures", NULL },
		{"show-signature", 'S', POPT_ARG_VAL, &list, 1,
			"show signature", NULL },
		{"remove-signature", 'r', POPT_ARG_VAL, &remove, 1,
			"remove signature" },
		{"export-signature", 'e',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctx.outsig, 0,"export signature to file", "<outsig>" },
		{"export-pubkey", 'K', POPT_ARG_STRING,
			&ctx.outkey, 0, "export pubkey to file", "<outkey>" },
		{"export-cert", 'C', POPT_ARG_STRING,
			&ctx.outcert, 0, "export signing cert to file",
			"<outcert>" },
		{"ascii-armor", 'a', POPT_ARG_VAL, &ctx.ascii, 1,
			"use ascii armoring", NULL },
		POPT_AUTOALIAS
		POPT_AUTOHELP
		POPT_TABLEEND
	};

	rc = pesign_context_init(ctxp);
	if (rc < 0) {
		fprintf(stderr, "Could not initialize context: %m\n");
		exit(1);
	}

	optCon = poptGetContext("pesign", argc, (const char **)argv, options,0);

	while ((rc = poptGetNextOpt(optCon)) > 0)
		;

	if (rc < -1) {
		fprintf(stderr, "pesign: Invalid argument: %s: %s\n",
			poptBadOption(optCon, 0), poptStrerror(rc));
		exit(1);
	}

	if (poptPeekArg(optCon)) {
		fprintf(stderr, "pesign: Invalid Argument: \"%s\"\n",
				poptPeekArg(optCon));
		exit(1);
	}

	poptFreeContext(optCon);

	rc = set_digest_parameters(&ctx.cms_ctx, digest_name);
	int is_help  = strcmp(digest_name, "help") ? 0 : 1;
	if (rc < 0) {
		if (!is_help) {
			fprintf(stderr, "Digest \"%s\" not found.\n",
				digest_name);
		}
		exit(!is_help);
	}

	int action = 0;
	if (ctx.insig)
		action |= IMPORT_SIGNATURE;

	if (ctx.outkey)
		action |= EXPORT_PUBKEY;

	if (ctx.outcert)
		action |= EXPORT_CERT;

	if (ctx.outsig)
		action |= EXPORT_SIGNATURE;

	if (remove != 0)
		action |= REMOVE_SIGNATURE;

	if (list != 0)
		action |= LIST_SIGNATURES;

	if (ctx.sign) {
		action |= GENERATE_SIGNATURE;
		if (!(action & EXPORT_SIGNATURE))
			action |= IMPORT_SIGNATURE;
	}

	if (ctx.hash)
		action |= GENERATE_DIGEST|PRINT_DIGEST;

	SECItem newsig;

	switch (action) {
		case NO_FLAGS:
			fprintf(stderr, "pesign: Nothing to do.\n");
			exit(0);
			break;
		/* add a signature from a file */
		case IMPORT_SIGNATURE:
			check_inputs(ctxp);
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			open_sig_input(ctxp);
			import_signature(ctxp);
			close_sig_input(ctxp);
			close_output(ctxp);
			break;
		case EXPORT_PUBKEY:
			rc = find_certificate(&ctx.cms_ctx);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctx.cms_ctx.certname);
				exit(1);
			}
			open_pubkey_output(ctxp);
			export_pubkey(ctxp);
			break;
		case EXPORT_CERT:
			rc = find_certificate(&ctx.cms_ctx);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctx.cms_ctx.certname);
				exit(1);
			}
			open_cert_output(ctxp);
			export_cert(ctxp);
			break;
		/* find a signature in the binary and save it to a file */
		case EXPORT_SIGNATURE:
			open_input(ctxp);
			open_sig_output(ctxp);
			if (ctx.signum > ctx.cms_ctx.num_signatures) {
				fprintf(stderr, "Invalid signature number.\n");
				exit(1);
			}
			SECItem *sig = ctx.cms_ctx.signatures[ctx.signum];
			export_signature(ctxp, sig);
			close_input(ctxp);
			close_sig_output(ctxp);
			break;
		/* remove a signature from the binary */
		case REMOVE_SIGNATURE:
			check_inputs(ctxp);
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			if (ctx.signum > ctx.cms_ctx.num_signatures) {
				fprintf(stderr, "Invalid signature number.\n");
				exit(1);
			}
			remove_signature(&ctx);
			close_output(ctxp);
			break;
		/* list signatures in the binary */
		case LIST_SIGNATURES:
			open_input(ctxp);
			list_signatures(ctxp);
			break;
		case GENERATE_DIGEST|PRINT_DIGEST:
			open_input(ctxp);
			generate_digest(ctxp, ctx.inpe);
			print_digest(ctxp);
			break;
		/* generate a signature and save it in a separate file */
		case EXPORT_SIGNATURE|GENERATE_SIGNATURE:
			rc = find_certificate(&ctx.cms_ctx);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctx.cms_ctx.certname);
				exit(1);
			}
			open_input(ctxp);
			open_sig_output(ctxp);
			generate_digest(ctxp, ctx.inpe);
			generate_signature(ctxp, &newsig);
			export_signature(ctxp, &newsig);
			break;
		/* generate a signature and embed it in the binary */
		case IMPORT_SIGNATURE|GENERATE_SIGNATURE:
			check_inputs(ctxp);
			rc = find_certificate(&ctx.cms_ctx);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctx.cms_ctx.certname);
				exit(1);
			}
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			generate_digest(ctxp, ctx.outpe);
			generate_signature(ctxp, &newsig);
			insert_signature(ctxp, &newsig);
			close_output(ctxp);
			break;
		default:
			fprintf(stderr, "Incompatible flags (0x%08x): ", action);
			for (int i = 1; i < FLAG_LIST_END; i <<= 1) {
				if (action & i)
					print_flag_name(stderr, i);
			}
			fprintf(stderr, "\n");
			exit(1);
	}
	pesign_context_fini(&ctx);
	return (rc < 0);
}
Beispiel #2
0
int
main (int argc, char **argv)
{
    int		 retval;
    PRFileDesc	*in_file;
    FILE	*out_file;	/* not PRFileDesc until SECU accepts it */
    int		 crequest, dresponse;
    int		 prequest, presponse;
    int		 ccert, vcert;
    const char	*db_dir, *date_str, *cert_usage_str, *name;
    const char	*responder_name, *responder_url, *signer_name;
    PRBool	 add_acceptable_responses, add_service_locator;
    SECItem	*data = NULL;
    PLOptState	*optstate;
    SECStatus	 rv;
    CERTCertDBHandle *handle = NULL;
    SECCertUsage cert_usage;
    PRTime	 verify_time;
    CERTCertificate *cert = NULL;
    PRBool ascii = PR_FALSE;

    retval = -1;		/* what we return/exit with on error */

    program_name = PL_strrchr(argv[0], '/');
    program_name = program_name ? (program_name + 1) : argv[0];

    in_file = PR_STDIN;
    out_file = stdout;

    crequest = 0;
    dresponse = 0;
    prequest = 0;
    presponse = 0;
    ccert = 0;
    vcert = 0;

    db_dir = NULL;
    date_str = NULL;
    cert_usage_str = NULL;
    name = NULL;
    responder_name = NULL;
    responder_url = NULL;
    signer_name = NULL;

    add_acceptable_responses = PR_FALSE;
    add_service_locator = PR_FALSE;

    optstate = PL_CreateOptState (argc, argv, "AHLPR:S:V:d:l:pr:s:t:u:w:");
    if (optstate == NULL) {
	SECU_PrintError (program_name, "PL_CreateOptState failed");
	return retval;
    }

    while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
	switch (optstate->option) {
	  case '?':
	    short_usage (program_name);
	    return retval;

	  case 'A':
	    add_acceptable_responses = PR_TRUE;
	    break;

	  case 'H':
	    long_usage (program_name);
	    return retval;

	  case 'L':
	    add_service_locator = PR_TRUE;
	    break;

	  case 'P':
	    presponse = 1;
	    break;

	  case 'R':
	    dresponse = 1;
	    name = optstate->value;
	    break;

	  case 'S':
	    ccert = 1;
	    name = optstate->value;
	    break;

	  case 'V':
	    vcert = 1;
	    name = optstate->value;
	    break;

	  case 'a':
	    ascii = PR_TRUE;
	    break;

	  case 'd':
	    db_dir = optstate->value;
	    break;

	  case 'l':
	    responder_url = optstate->value;
	    break;

	  case 'p':
	    prequest = 1;
	    break;

	  case 'r':
	    crequest = 1;
	    name = optstate->value;
	    break;

	  case 's':
	    signer_name = optstate->value;
	    break;

	  case 't':
	    responder_name = optstate->value;
	    break;

	  case 'u':
	    cert_usage_str = optstate->value;
	    break;

	  case 'w':
	    date_str = optstate->value;
	    break;
	}
    }

    PL_DestroyOptState(optstate);

    if ((crequest + dresponse + prequest + presponse + ccert + vcert) != 1) {
	PR_fprintf (PR_STDERR, "%s: must specify exactly one command\n\n",
		    program_name);
	short_usage (program_name);
	return retval;
    }

    if (vcert) {
	if (cert_usage_str == NULL) {
	    PR_fprintf (PR_STDERR, "%s: verification requires cert usage\n\n",
			program_name);
	    short_usage (program_name);
	    return retval;
	}

	rv = cert_usage_from_char (cert_usage_str, &cert_usage);
	if (rv != SECSuccess) {
	    PR_fprintf (PR_STDERR, "%s: invalid cert usage (\"%s\")\n\n",
			program_name, cert_usage_str);
	    long_usage (program_name);
	    return retval;
	}
    }

    if (ccert + vcert) {
	if (responder_url != NULL || responder_name != NULL) {
	    /*
	     * To do a full status check, both the URL and the cert name
	     * of the responder must be specified if either one is.
	     */
	    if (responder_url == NULL || responder_name == NULL) {
		if (responder_url == NULL)
		    PR_fprintf (PR_STDERR,
				"%s: must also specify responder location\n\n",
				program_name);
		else
		    PR_fprintf (PR_STDERR,
				"%s: must also specify responder name\n\n",
				program_name);
		short_usage (program_name);
		return retval;
	    }
	}

	if (date_str != NULL) {
	    rv = DER_AsciiToTime (&verify_time, (char *) date_str);
	    if (rv != SECSuccess) {
		SECU_PrintError (program_name, "error converting time string");
		PR_fprintf (PR_STDERR, "\n");
		long_usage (program_name);
		return retval;
	    }
	} else {
	    verify_time = PR_Now();
	}
    }

    retval = -2;		/* errors change from usage to runtime */

    /*
     * Initialize the NSPR and Security libraries.
     */
    PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    db_dir = SECU_ConfigDirectory (db_dir);
    rv = NSS_Init (db_dir);
    if (rv != SECSuccess) {
	SECU_PrintError (program_name, "NSS_Init failed");
	goto prdone;
    }
    SECU_RegisterDynamicOids();

    if (prequest + presponse) {
	MAKE_FILE_BINARY(stdin);
	data = read_file_into_item (in_file, siBuffer);
	if (data == NULL) {
	    SECU_PrintError (program_name, "problem reading input");
	    goto nssdone;
	}
    }

    if (crequest + dresponse + presponse + ccert + vcert) {
	handle = CERT_GetDefaultCertDB();
	if (handle == NULL) {
	    SECU_PrintError (program_name, "problem getting certdb handle");
	    goto nssdone;
	}

	/*
	 * It would be fine to do the enable for all of these commands,
	 * but this way we check that everything but an overall verify
	 * can be done without it.  That is, that the individual pieces
	 * work on their own.
	 */
	if (vcert) {
	    rv = CERT_EnableOCSPChecking (handle);
	    if (rv != SECSuccess) {
		SECU_PrintError (program_name, "error enabling OCSP checking");
		goto nssdone;
	    }
	}

	if ((ccert + vcert) && (responder_name != NULL)) {
	    rv = CERT_SetOCSPDefaultResponder (handle, responder_url,
					       responder_name);
	    if (rv != SECSuccess) {
		SECU_PrintError (program_name,
				 "error setting default responder");
		goto nssdone;
	    }

	    rv = CERT_EnableOCSPDefaultResponder (handle);
	    if (rv != SECSuccess) {
		SECU_PrintError (program_name,
				 "error enabling default responder");
		goto nssdone;
	    }
	}
    }

#define NOTYET(opt)							\
	{								\
	    PR_fprintf (PR_STDERR, "%s not yet working\n", opt);	\
	    exit (-1);							\
	}

    if (name) {
        cert = find_certificate(handle, name, ascii);
    }

    if (crequest) {
	if (signer_name != NULL) {
	    NOTYET("-s");
	}
	rv = create_request (out_file, handle, cert, add_service_locator,
			     add_acceptable_responses);
    } else if (dresponse) {
	if (signer_name != NULL) {
	    NOTYET("-s");
	}
	rv = dump_response (out_file, handle, cert, responder_url);
    } else if (prequest) {
	rv = print_request (out_file, data);
    } else if (presponse) {
	rv = print_response (out_file, data, handle);
    } else if (ccert) {
	if (signer_name != NULL) {
	    NOTYET("-s");
	}
	rv = get_cert_status (out_file, handle, cert, name, verify_time);
    } else if (vcert) {
	if (signer_name != NULL) {
	    NOTYET("-s");
	}
	rv = verify_cert (out_file, handle, cert, name, cert_usage, verify_time);
    }

    if (rv != SECSuccess)
	SECU_PrintError (program_name, "error performing requested operation");
    else
	retval = 0;

nssdone:
    if (cert) {
        CERT_DestroyCertificate(cert);
    }

    if (data != NULL) {
	SECITEM_FreeItem (data, PR_TRUE);
    }

    if (handle != NULL) {
 	CERT_DisableOCSPDefaultResponder(handle);        
 	CERT_DisableOCSPChecking (handle);
    }

    if (NSS_Shutdown () != SECSuccess) {
	retval = 1;
    }

prdone:
    PR_Cleanup ();
    return retval;
}
Beispiel #3
0
int
main(int argc, char *argv[])
{
	int rc;

	pesign_context *ctxp;

	int list = 0;
	int remove = 0;
	int daemon = 0;
	int fork = 1;
	int padding = 0;
	int need_db = 0;

	char *digest_name = "sha256";
	char *tokenname = "NSS Certificate DB";
	char *origtoken = tokenname;
	char *certname = NULL;
	char *certdir = "/etc/pki/pesign";
	char *signum = NULL;

	rc = pesign_context_new(&ctxp);
	if (rc < 0) {
		fprintf(stderr, "Could not initialize context: %m\n");
		exit(1);
	}

	poptContext optCon;
	struct poptOption options[] = {
		{NULL, '\0', POPT_ARG_INTL_DOMAIN, "pesign" },
		{"in", 'i', POPT_ARG_STRING, &ctxp->infile, 0,
			"specify input file", "<infile>"},
		{"out", 'o', POPT_ARG_STRING, &ctxp->outfile, 0,
			"specify output file", "<outfile>" },
		{"certficate", 'c', POPT_ARG_STRING, &certname, 0,
			"specify certificate nickname",
			"<certificate nickname>" },
		{"certdir", 'n', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
			&certdir, 0,
			"specify nss certificate database directory",
			"<certificate directory path>" },
		{"force", 'f', POPT_ARG_VAL, &ctxp->force,  1,
			"force overwriting of output file", NULL },
		{"sign", 's', POPT_ARG_VAL, &ctxp->sign, 1,
			"create a new signature", NULL },
		{"hash", 'h', POPT_ARG_VAL, &ctxp->hash, 1,
			"hash binary", NULL },
		{"digest_type", 'd', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
			&digest_name, 0, "digest type to use for pe hash" },
		{"import-signed-certificate", 'm',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctxp->insig, 0,"import signature from file", "<insig>" },
		{"export-signed-attributes", 'E',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctxp->outsattrs, 0, "export signed attributes to file",
			"<signed_attributes_file>" },
		{"import-signed-attributes", 'I',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctxp->insattrs, 0,
			"import signed attributes from file",
			"<signed_attributes_file>" },
		{"import-raw-signature", 'R',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &ctxp->rawsig,
			0, "import raw signature from file", "<inraw>" },
		{"signature-number", 'u', POPT_ARG_STRING, &signum, 0,
			"specify which signature to operate on","<sig-number>"},
		{"list-signatures", 'l',
			POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,
			&list, 1, "list signatures", NULL },
		{"nss-token", 't', POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,
			&tokenname, 0, "NSS token holding signing key" },
		{"show-signature", 'S', POPT_ARG_VAL, &list, 1,
			"show signature", NULL },
		{"remove-signature", 'r', POPT_ARG_VAL, &remove, 1,
			"remove signature" },
		{"export-signature", 'e',
			POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,
			&ctxp->outsig, 0,
			"export signature to file", "<outsig>" },
		{"export-pubkey", 'K', POPT_ARG_STRING,
			&ctxp->outkey, 0, "export pubkey to file", "<outkey>" },
		{"export-cert", 'C', POPT_ARG_STRING,
			&ctxp->outcert, 0, "export signing cert to file",
			"<outcert>" },
		{"ascii-armor", 'a', POPT_ARG_VAL, &ctxp->ascii, 1,
			"use ascii armoring", NULL },
		{"daemonize", 'D', POPT_ARG_VAL, &daemon, 1,
			"run as a daemon process", NULL },
		{"nofork", 'N', POPT_ARG_VAL, &fork, 0,
			"don't fork when daemonizing", NULL },
		{"verbose", 'v', POPT_ARG_VAL, &ctxp->verbose, 1,
			"be very verbose", NULL },
		{"padding", 'P', POPT_ARG_VAL,
			&padding, 1, "pad data section", NULL },
		POPT_AUTOALIAS
		POPT_AUTOHELP
		POPT_TABLEEND
	};

	optCon = poptGetContext("pesign", argc, (const char **)argv, options,0);

	rc = poptReadDefaultConfig(optCon, 0);
	if (rc < 0 && !(rc == POPT_ERROR_ERRNO && errno == ENOENT)) {
		fprintf(stderr, "pesign: poptReadDefaultConfig failed: %s\n",
		poptStrerror(rc));
		exit(1);
	}

	while ((rc = poptGetNextOpt(optCon)) > 0)
		;

	if (rc < -1) {
		fprintf(stderr, "pesign: Invalid argument: %s: %s\n",
			poptBadOption(optCon, 0), poptStrerror(rc));
		exit(1);
	}

	if (poptPeekArg(optCon)) {
		fprintf(stderr, "pesign: Invalid Argument: \"%s\"\n",
				poptPeekArg(optCon));
		exit(1);
	}

	poptFreeContext(optCon);

	if (signum) {
		errno = 0;
		ctxp->signum = strtol(signum, NULL, 0);
		if (errno != 0) {
			fprintf(stderr, "invalid signature number: %m\n");
			exit(1);
		}
	}

	int action = 0;
	if (daemon)
		action |= DAEMONIZE;

	if (ctxp->rawsig) {
		action |= IMPORT_RAW_SIGNATURE;
		need_db = 1;
	}

	if (ctxp->insattrs)
		action |= IMPORT_SATTRS;

	if (ctxp->outsattrs)
		action |= EXPORT_SATTRS;

	if (ctxp->insig)
		action |= IMPORT_SIGNATURE;

	if (ctxp->outkey) {
		action |= EXPORT_PUBKEY;
		need_db = 1;
	}

	if (ctxp->outcert) {
		action |= EXPORT_CERT;
		need_db = 1;
	}

	if (ctxp->outsig)
		action |= EXPORT_SIGNATURE;

	if (remove != 0)
		action |= REMOVE_SIGNATURE;

	if (list != 0)
		action |= LIST_SIGNATURES;

	if (ctxp->sign) {
		action |= GENERATE_SIGNATURE;
		if (!(action & EXPORT_SIGNATURE))
			action |= IMPORT_SIGNATURE;
		need_db = 1;
	}

	if (ctxp->hash)
		action |= GENERATE_DIGEST|PRINT_DIGEST;

	if (!daemon) {
		SECStatus status;
		if (need_db)
			status = NSS_Init(certdir);
		else
			status = NSS_NoDB_Init(NULL);
		if (status != SECSuccess) {
			fprintf(stderr, "Could not initialize nss: %s\n",
				PORT_ErrorToString(PORT_GetError()));
			exit(1);
		}

		status = register_oids(ctxp->cms_ctx);
		if (status != SECSuccess) {
			fprintf(stderr, "Could not register OIDs\n");
			exit(1);
		}
	}

	rc = set_digest_parameters(ctxp->cms_ctx, digest_name);
	int is_help  = strcmp(digest_name, "help") ? 0 : 1;
	if (rc < 0) {
		if (!is_help) {
			fprintf(stderr, "Digest \"%s\" not found.\n",
				digest_name);
		}
		exit(!is_help);
	}

	ctxp->cms_ctx->tokenname = tokenname ?
		PORT_ArenaStrdup(ctxp->cms_ctx->arena, tokenname) : NULL;
	if (tokenname && !ctxp->cms_ctx->tokenname) {
		fprintf(stderr, "could not allocate token name: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		exit(1);
	}
	if (tokenname != origtoken)
		free(tokenname);

	ctxp->cms_ctx->certname = certname ?
		PORT_ArenaStrdup(ctxp->cms_ctx->arena, certname) : NULL;
	if (certname && !ctxp->cms_ctx->certname) {
		fprintf(stderr, "could not allocate certificate name: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		exit(1);
	}
	if (certname)
		free(certname);


	if (ctxp->sign) {
		if (!ctxp->cms_ctx->certname) {
			fprintf(stderr, "pesign: signing requested but no "
				"certificate nickname provided\n");
			exit(1);
		}
	}

	ssize_t sigspace = 0;

	switch (action) {
		case NO_FLAGS:
			fprintf(stderr, "pesign: Nothing to do.\n");
			exit(0);
			break;
		/* in this case we have the actual binary signature and the
		 * signing cert, but not the pkcs7ish certificate that goes
		 * with it.
		 */
		case IMPORT_RAW_SIGNATURE|IMPORT_SATTRS:
			check_inputs(ctxp);
			rc = find_certificate(ctxp->cms_ctx, 0);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctxp->cms_ctx->certname);
				exit(1);
			}
			open_rawsig_input(ctxp);
			open_sattr_input(ctxp);
			import_raw_signature(ctxp);
			close_sattr_input(ctxp);
			close_rawsig_input(ctxp);

			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			generate_digest(ctxp->cms_ctx, ctxp->outpe, 1);
			sigspace = calculate_signature_space(ctxp->cms_ctx,
								ctxp->outpe);
			allocate_signature_space(ctxp->outpe, sigspace);
			generate_signature(ctxp->cms_ctx);
			insert_signature(ctxp->cms_ctx, ctxp->signum);
			close_output(ctxp);
			break;
		case EXPORT_SATTRS:
			open_input(ctxp);
			open_sattr_output(ctxp);
			generate_digest(ctxp->cms_ctx, ctxp->inpe, 1);
			generate_sattr_blob(ctxp);
			close_sattr_output(ctxp);
			close_input(ctxp);
			break;
		/* add a signature from a file */
		case IMPORT_SIGNATURE:
			check_inputs(ctxp);
			if (ctxp->signum > ctxp->cms_ctx->num_signatures + 1) {
				fprintf(stderr, "Invalid signature number.\n");
				exit(1);
			}
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			open_sig_input(ctxp);
			parse_signature(ctxp);
			sigspace = get_sigspace_extend_amount(ctxp->cms_ctx,
					ctxp->outpe, &ctxp->cms_ctx->newsig);
			allocate_signature_space(ctxp->outpe, sigspace);
			check_signature_space(ctxp);
			insert_signature(ctxp->cms_ctx, ctxp->signum);
			close_sig_input(ctxp);
			close_output(ctxp);
			break;
		case EXPORT_PUBKEY:
			rc = find_certificate(ctxp->cms_ctx, 1);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctxp->cms_ctx->certname);
				exit(1);
			}
			open_pubkey_output(ctxp);
			export_pubkey(ctxp);
			break;
		case EXPORT_CERT:
			rc = find_certificate(ctxp->cms_ctx, 0);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctxp->cms_ctx->certname);
				exit(1);
			}
			open_cert_output(ctxp);
			export_cert(ctxp);
			break;
		/* find a signature in the binary and save it to a file */
		case EXPORT_SIGNATURE:
			open_input(ctxp);
			open_sig_output(ctxp);
			if (ctxp->signum > ctxp->cms_ctx->num_signatures) {
				fprintf(stderr, "Invalid signature number.\n");
				exit(1);
			}
			if (ctxp->signum < 0)
				ctxp->signum = 0;
			if (ctxp->signum >= ctxp->cms_ctx->num_signatures) {
				fprintf(stderr, "No valid signature #%d.\n",
					ctxp->signum);
				exit(1);
			}
			memcpy(&ctxp->cms_ctx->newsig,
				ctxp->cms_ctx->signatures[ctxp->signum],
				sizeof (ctxp->cms_ctx->newsig));
			export_signature(ctxp->cms_ctx, ctxp->outsigfd, ctxp->ascii);
			close_input(ctxp);
			close_sig_output(ctxp);
			memset(&ctxp->cms_ctx->newsig, '\0',
				sizeof (ctxp->cms_ctx->newsig));
			break;
		/* remove a signature from the binary */
		case REMOVE_SIGNATURE:
			check_inputs(ctxp);
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			if (ctxp->signum < 0 ||
					ctxp->signum >=
					ctxp->cms_ctx->num_signatures) {
				fprintf(stderr, "Invalid signature number %d.  "
					"Must be between 0 and %d.\n",
					ctxp->signum,
					ctxp->cms_ctx->num_signatures - 1);
				exit(1);
			}
			remove_signature(ctxp);
			close_output(ctxp);
			break;
		/* list signatures in the binary */
		case LIST_SIGNATURES:
			open_input(ctxp);
			list_signatures(ctxp);
			break;
		case GENERATE_DIGEST|PRINT_DIGEST:
			open_input(ctxp);
			generate_digest(ctxp->cms_ctx, ctxp->inpe, padding);
			print_digest(ctxp);
			break;
		/* generate a signature and save it in a separate file */
		case EXPORT_SIGNATURE|GENERATE_SIGNATURE:
			rc = find_certificate(ctxp->cms_ctx, 1);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctxp->cms_ctx->certname);
				exit(1);
			}
			open_input(ctxp);
			open_sig_output(ctxp);
			generate_digest(ctxp->cms_ctx, ctxp->inpe, 1);
			generate_signature(ctxp->cms_ctx);
			export_signature(ctxp->cms_ctx, ctxp->outsigfd, ctxp->ascii);
			break;
		/* generate a signature and embed it in the binary */
		case IMPORT_SIGNATURE|GENERATE_SIGNATURE:
			check_inputs(ctxp);
			rc = find_certificate(ctxp->cms_ctx, 1);
			if (rc < 0) {
				fprintf(stderr, "pesign: Could not find "
					"certificate %s\n",
					ctxp->cms_ctx->certname);
				exit(1);
			}
			if (ctxp->signum > ctxp->cms_ctx->num_signatures + 1) {
				fprintf(stderr, "Invalid signature number.\n");
				exit(1);
			}
			open_input(ctxp);
			open_output(ctxp);
			close_input(ctxp);
			generate_digest(ctxp->cms_ctx, ctxp->outpe, 1);
			sigspace = calculate_signature_space(ctxp->cms_ctx,
							     ctxp->outpe);
			allocate_signature_space(ctxp->outpe, sigspace);
			generate_digest(ctxp->cms_ctx, ctxp->outpe, 1);
			generate_signature(ctxp->cms_ctx);
			insert_signature(ctxp->cms_ctx, ctxp->signum);
			close_output(ctxp);
			break;
		case DAEMONIZE:
			rc = daemonize(ctxp->cms_ctx, certdir, fork);
			break;
		default:
			fprintf(stderr, "Incompatible flags (0x%08x): ", action);
			for (int i = 1; i < FLAG_LIST_END; i <<= 1) {
				if (action & i)
					print_flag_name(stderr, i);
			}
			fprintf(stderr, "\n");
			exit(1);
	}
	pesign_context_free(ctxp);

	if (!daemon) {
		SECStatus status = NSS_Shutdown();
		if (status != SECSuccess) {
			fprintf(stderr, "could not shut down NSS: %s",
				PORT_ErrorToString(PORT_GetError()));
			exit(1);
		}
	}

	return (rc < 0);
}