Exemplo n.º 1
0
static int
generate_spc_pe_image_data(cms_context *cms, SECItem *spidp)
{
	SpcPeImageData spid;

	SECITEM_AllocItem(cms->arena, &spid.flags, 1);
	if (!spid.flags.data)
		return -1;
	spid.flags.data[0] = 0;

	char obsolete[28] = "";
	int rc;
	rc = generate_spc_link(cms, &spid.link, SpcLinkTypeFile, obsolete, 0);
	if (rc < 0)
		return rc;

	if (SEC_ASN1EncodeItem(cms->arena, spidp, &spid,
			SpcPeImageDataTemplate) == NULL) {
		cms->log(cms, LOG_ERR, "could not encode SpcPeImageData: %s",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}

	/* XXX OMG FIX THIS */
	/* manually bang it from NULL to BIT STRING because I can't figure out
	 * how to make the f*****g templates work right for the bitstring size
	 */
	spidp->data[2] = DER_BIT_STRING;
	return 0;
}
Exemplo n.º 2
0
static int
generate_spc_digest_info(cms_context *cms, SECItem *dip)
{
	DigestInfo di;
	memset(&di, '\0', sizeof (di));

	if (generate_algorithm_id(cms, &di.digestAlgorithm,
			digest_get_digest_oid(cms)) < 0)
		return -1;
	int i = cms->selected_digest;
	memcpy(&di.digest, cms->digests[i].pe_digest, sizeof (di.digest));

	if (content_is_empty(di.digest.data, di.digest.len)) {
		cms->log(cms, LOG_ERR, "got empty digest");
		return -1;
	}

	if (SEC_ASN1EncodeItem(cms->arena, dip, &di,
						DigestInfoTemplate) == NULL) {
		cms->log(cms, LOG_ERR, "could not encode DigestInfo: %s",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}
	return 0;
}
Exemplo n.º 3
0
static int
generate_spc_indirect_data_content(cms_context *cms, SECItem *idcp)
{
	SpcIndirectDataContent idc;
	memset(&idc, '\0', sizeof (idc));
	int rc;

	rc = generate_spc_attribute_yadda_yadda(cms, &idc.data);
	if (rc < 0)
		return rc;

	rc = generate_spc_digest_info(cms, &idc.messageDigest);
	if (rc < 0) {
		SECITEM_FreeItem(&idc.data, PR_FALSE);
		return rc;
	}

	if (SEC_ASN1EncodeItem(cms->arena, idcp, &idc,
			SpcIndirectDataContentTemplate) == NULL) {
		cms->log(cms, LOG_ERR, "could not encode "
			"SpcIndirectDataContent: %s",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}
	return 0;
}
Exemplo n.º 4
0
static int
generate_spc_pe_image_data(PRArenaPool *arena, SECItem *spidp)
{
	SpcPeImageData spid;

	SECITEM_AllocItem(arena, &spid.flags, 1);
	if (!spid.flags.data)
		return -1;
	spid.flags.data[0] = 0;

	char obsolete[28] = "\0<\0<\0<\0O\0b\0s\0o\0l\0e\0t\0e\0>\0>\0>";
	if (generate_spc_link(arena, &spid.link, SpcLinkTypeFile, obsolete,
			28) < 0) {
		fprintf(stderr, "got here %s:%d\n",__func__,__LINE__);
		return -1;
	}

	if (SEC_ASN1EncodeItem(arena, spidp, &spid,
			SpcPeImageDataTemplate) == NULL) {
		fprintf(stderr, "Could not encode SpcPeImageData: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}

	/* XXX OMG FIX THIS */
	/* manually bang it from NULL to BIT STRING because I can't figure out
	 * how to make the f*****g templates work right for the bitstring size
	 */
	spidp->data[2] = DER_BIT_STRING;
	return 0;
}
Exemplo n.º 5
0
/* Generate DER for SpcAttributeTypeAndValue, which is basically just
 * a DER_SEQUENCE containing the OID 1.3.6.1.4.1.311.2.1.15
 * (SPC_PE_IMAGE_DATA_OBJID) and the SpcPeImageData.
 */
static int
generate_spc_attribute_yadda_yadda(cms_context *cms, SECItem *ataovp)
{
	SpcAttributeTypeAndOptionalValue ataov;
	memset(&ataov, '\0', sizeof (ataov));

	int rc;

	rc = get_ms_oid_secitem(SPC_PE_IMAGE_DATA_OBJID, &ataov.contentType);
	if (rc < 0) {
		cms->log(cms, LOG_ERR, "could not get SPC_PE_IMAGE_DATA_OBJID");
		return -1;
	}

	rc = generate_spc_pe_image_data(cms, &ataov.value);
	if (rc < 0)
		return rc;

	if (SEC_ASN1EncodeItem(cms->arena, ataovp, &ataov,
			SpcAttributeTypeAndOptionalValueTemplate) == NULL) {
		cms->log(cms, LOG_ERR, "could not encode "
			"SpcAttributeTypeAndOptionalValue: %s",
			PORT_ErrorToString(PORT_GetError()));

		return -1;
	}
	return 0;
}
Exemplo n.º 6
0
/* Generate DER for SpcAttributeTypeAndValue, which is basically just
 * a DER_SEQUENCE containing the OID 1.3.6.1.4.1.311.2.1.15
 * (SPC_PE_IMAGE_DATA_OBJID) and the SpcPeImageData.
 */
static int
generate_spc_attribute_yadda_yadda(PRArenaPool *arena, SECItem *ataovp)
{
	SpcAttributeTypeAndOptionalValue ataov;
	memset(&ataov, '\0', sizeof (ataov));

	if (get_ms_oid_secitem(SPC_PE_IMAGE_DATA_OBJID, &ataov.contentType) < 0){
		fprintf(stderr, "got here %s:%d\n",__func__,__LINE__);
		return -1;
	}

	if (generate_spc_pe_image_data(arena, &ataov.value) < 0) {
		fprintf(stderr, "got here %s:%d\n",__func__,__LINE__);
		return -1;
	}

	if (SEC_ASN1EncodeItem(arena, ataovp, &ataov,
			SpcAttributeTypeAndOptionalValueTemplate) == NULL) {
		fprintf(stderr,
			"Could not encode SpcAttributeTypeAndOptionalValue:"
			"%s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}
	return 0;
}
Exemplo n.º 7
0
static int
generate_spc_indirect_data_content(PRArenaPool *arena, SECItem *idcp,
				cms_context *ctx)
{
	SpcIndirectDataContent idc;
	memset(&idc, '\0', sizeof (idc));

	if (generate_spc_attribute_yadda_yadda(arena, &idc.data) < 0) {
		fprintf(stderr, "got here %s:%d\n",__func__,__LINE__);
		return -1;
	}

	if (generate_spc_digest_info(arena, &idc.messageDigest, ctx) < 0) {
		fprintf(stderr, "got here %s:%d\n",__func__,__LINE__);
		return -1;
	}

	if (SEC_ASN1EncodeItem(arena, idcp, &idc,
			SpcIndirectDataContentTemplate) == NULL) {
		fprintf(stderr,
			"Could not encode SpcIndirectDataContent: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}
	return 0;
}
Exemplo n.º 8
0
int
generate_sattr_blob(pesign_context *ctx)
{
	int rc;
	SECItem sa;
	SpcContentInfo ci;

	memset(&ci, '\0', sizeof (ci));
	rc = generate_spc_content_info(ctx->cms_ctx, &ci);
	if (rc < 0) {
		fprintf(stderr, "Could not generate content info: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		exit(1);
	}

	rc = generate_signed_attributes(ctx->cms_ctx, &sa);
	if (rc < 0) {
		fprintf(stderr, "Could not generate signed attributes: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		exit(1);
	}

	return write(ctx->outsattrsfd, sa.data, sa.len);
}
Exemplo n.º 9
0
static int
generate_spc_digest_info(PRArenaPool *arena, SECItem *dip, cms_context *ctx)
{
	DigestInfo di;
	memset(&di, '\0', sizeof (di));

	if (generate_algorithm_id(ctx, &di.digestAlgorithm,
			ctx->digest_oid_tag) < 0)
		return -1;
	memcpy(&di.digest, ctx->pe_digest, sizeof (di.digest));

	if (SEC_ASN1EncodeItem(arena, dip, &di, DigestInfoTemplate) == NULL) {
		fprintf(stderr, "Could not encode DigestInfo: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}
	return 0;
}
Exemplo n.º 10
0
void
SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg,
                 ...)
{
    va_list args;
    PRErrorCode err = PORT_GetError();
    const char *errString = PORT_ErrorToString(err);

    va_start(args, msg);

    SECU_Indent(out, level);
    fprintf(out, "%s: ", progName);
    vfprintf(out, msg, args);
    if (errString != NULL && PORT_Strlen(errString) > 0)
        fprintf(out, ": %s\n", errString);
    else
        fprintf(out, ": error %d\n", (int)err);

    va_end(args);
}
Exemplo n.º 11
0
/* before you run this, you'll need to enroll your CA with:
 * certutil -A -n 'my CA' -d /etc/pki/pesign -t CT,CT,CT -i ca.crt
 * And you'll need to enroll the private key like this:
 * pk12util -d /etc/pki/pesign/ -i Peter\ Jones.p12 
 */
int
generate_signature(pesign_context *p_ctx, SECItem *newsig)
{
	int rc = 0;
	cms_context *ctx = &p_ctx->cms_ctx;

	assert(ctx->pe_digest != NULL);

	SECItem sd_der;
	memset(&sd_der, '\0', sizeof(sd_der));
	rc = generate_spc_signed_data(&sd_der, ctx);
	if (rc < 0) {
		fprintf(stderr, "Could not create signed data: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}

	memcpy(newsig, &sd_der, sizeof (*newsig));
	return 0;
}
Exemplo n.º 12
0
int
generate_spc_string(PRArenaPool *arena, SECItem *ssp, char *str, int len)
{
	SpcString ss;
	memset(&ss, '\0', sizeof (ss));

	SECITEM_AllocItem(arena, &ss.unicode, len);
	if (!ss.unicode.data && len != 0)
		return -1;

	memcpy(ss.unicode.data, str, len);
	ss.unicode.type = siBMPString;

	if (SEC_ASN1EncodeItem(arena, ssp, &ss, SpcStringTemplate) == NULL) {
		fprintf(stderr, "Could not encode SpcString: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}

	return 0;
}
Exemplo n.º 13
0
int
cms_context_init(cms_context *ctx)
{
	SECStatus status;
	
	status = NSS_InitReadWrite("/etc/pki/pesign");
	if (status != SECSuccess)
		return -1;

	status = register_oids();
	if (status != SECSuccess)
		return -1;

	memset(ctx, '\0', sizeof (*ctx));

	ctx->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
	if (!ctx->arena) {
		fprintf(stderr, "Could not create cryptographic arena: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		return -1;
	}

	return 0;
}
Exemplo n.º 14
0
/**
 * Check a canonical sig+rrset and signature against a dnskey
 * @param buf: buffer with data to verify, the first rrsig part and the
 *	canonicalized rrset.
 * @param algo: DNSKEY algorithm.
 * @param sigblock: signature rdata field from RRSIG
 * @param sigblock_len: length of sigblock data.
 * @param key: public key data from DNSKEY RR.
 * @param keylen: length of keydata.
 * @param reason: bogus reason in more detail.
 * @return secure if verification succeeded, bogus on crypto failure,
 *	unchecked on format errors and alloc failures.
 */
enum sec_status
verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, 
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
	char** reason)
{
	/* uses libNSS */
	/* large enough for the different hashes */
	unsigned char hash[HASH_LENGTH_MAX];
	unsigned char hash2[HASH_LENGTH_MAX*2];
	HASH_HashType htype = 0;
	SECKEYPublicKey* pubkey = NULL;
	SECItem secsig = {siBuffer, sigblock, sigblock_len};
	SECItem sechash = {siBuffer, hash, 0};
	SECStatus res;
	unsigned char* prefix = NULL; /* prefix for hash, RFC3110, RFC5702 */
	size_t prefixlen = 0;
	int err;

	if(!nss_setup_key_digest(algo, &pubkey, &htype, key, keylen,
		&prefix, &prefixlen)) {
		verbose(VERB_QUERY, "verify: failed to setup key");
		*reason = "use of key for crypto failed";
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_bogus;
	}

#if defined(USE_DSA) && defined(USE_SHA1)
	/* need to convert DSA, ECDSA signatures? */
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3)) {
		if(sigblock_len == 1+2*SHA1_LENGTH) {
			secsig.data ++;
			secsig.len --;
		} else {
			SECItem* p = DSAU_DecodeDerSig(&secsig);
			if(!p) {
				verbose(VERB_QUERY, "verify: failed DER decode");
				*reason = "signature DER decode failed";
				SECKEY_DestroyPublicKey(pubkey);
				return sec_status_bogus;
			}
			if(SECITEM_CopyItem(pubkey->arena, &secsig, p)) {
				log_err("alloc failure in DER decode");
				SECKEY_DestroyPublicKey(pubkey);
				SECITEM_FreeItem(p, PR_TRUE);
				return sec_status_unchecked;
			}
			SECITEM_FreeItem(p, PR_TRUE);
		}
	}
#endif /* USE_DSA */

	/* do the signature cryptography work */
	/* hash the data */
	sechash.len = HASH_ResultLen(htype);
	if(sechash.len > sizeof(hash)) {
		verbose(VERB_QUERY, "verify: hash too large for buffer");
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_unchecked;
	}
	if(HASH_HashBuf(htype, hash, (unsigned char*)sldns_buffer_begin(buf),
		(unsigned int)sldns_buffer_limit(buf)) != SECSuccess) {
		verbose(VERB_QUERY, "verify: HASH_HashBuf failed");
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_unchecked;
	}
	if(prefix) {
		int hashlen = sechash.len;
		if(prefixlen+hashlen > sizeof(hash2)) {
			verbose(VERB_QUERY, "verify: hashprefix too large");
			SECKEY_DestroyPublicKey(pubkey);
			return sec_status_unchecked;
		}
		sechash.data = hash2;
		sechash.len = prefixlen+hashlen;
		memcpy(sechash.data, prefix, prefixlen);
		memmove(sechash.data+prefixlen, hash, hashlen);
	}

	/* verify the signature */
	res = PK11_Verify(pubkey, &secsig, &sechash, NULL /*wincx*/);
	SECKEY_DestroyPublicKey(pubkey);

	if(res == SECSuccess) {
		return sec_status_secure;
	}
	err = PORT_GetError();
	if(err != SEC_ERROR_BAD_SIGNATURE) {
		/* failed to verify */
		verbose(VERB_QUERY, "verify: PK11_Verify failed: %s",
			PORT_ErrorToString(err));
		/* if it is not supported, like ECC is removed, we get,
		 * SEC_ERROR_NO_MODULE */
		if(err == SEC_ERROR_NO_MODULE)
			return sec_status_unchecked;
		/* but other errors are commonly returned
		 * for a bad signature from NSS.  Thus we return bogus,
		 * not unchecked */
		*reason = "signature crypto failed";
		return sec_status_bogus;
	}
	verbose(VERB_QUERY, "verify: signature mismatch: %s",
		PORT_ErrorToString(err));
	*reason = "signature crypto failed";
	return sec_status_bogus;
}
Exemplo n.º 15
0
int
generate_spc_signed_data(SECItem *sdp, cms_context *ctx)
{
	SignedData sd;

	if (!sdp)
		return -1;

	memset(&sd, '\0', sizeof (sd));

	if (SEC_ASN1EncodeInteger(ctx->arena, &sd.version, 1) == NULL)
		return -1;

	if (generate_algorithm_id_list(&sd.algorithms, ctx) < 0)
		goto err;
	
	if (generate_spc_content_info(&sd.cinfo, ctx) < 0)
		goto err_algorithms;

	if (generate_certificate_list(&sd.certificates, ctx) < 0)
		goto err_cinfo;

	sd.crls = NULL;

	if (generate_signerInfo_list(&sd.signerInfos, ctx) < 0)
		goto err_certificate_list;

	SECItem encoded = { 0, };
	if (SEC_ASN1EncodeItem(ctx->arena, &encoded, &sd, SignedDataTemplate)
			== NULL) {
		fprintf(stderr, "Could not encode SignedData: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		goto err_signer_infos;
	}

	ContentInfo sdw;
	memset(&sdw, '\0', sizeof (sdw));

	SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS7_SIGNED_DATA);

	memcpy(&sdw.contentType, &oid->oid, sizeof (sdw.contentType));
	memcpy(&sdw.content, &encoded, sizeof (sdw.content));

	SECItem wrapper = { 0, };
	if (SEC_ASN1EncodeItem(ctx->arena, &wrapper, &sdw,
			ContentInfoTemplate) == NULL) {
		fprintf(stderr, "Could not encode SignedData: %s\n",
			PORT_ErrorToString(PORT_GetError()));
		goto err_signed_data;
	}

	memcpy(sdp, &wrapper, sizeof(*sdp));
	return 0;
err_signed_data:
	SECITEM_FreeItem(&encoded, PR_FALSE);
err_signer_infos:
	free_signerInfo_list(sd.signerInfos, ctx);
err_certificate_list:
	free_certificate_list(sd.certificates, ctx);
err_cinfo:
	free_spc_content_info(&sd.cinfo, ctx);
err_algorithms:
	free_algorithm_list(sd.algorithms, ctx);
err:
#if 0
	SECITEM_FreeItem(&sd.version, PR_TRUE);
#endif
	return -1;
}
Exemplo n.º 16
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);
}