cmsutil.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:38k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * cmsutil -- A command to work with CMS data
- *
- * $Id: cmsutil.c,v 1.15 2000/10/11 07:21:38 wtc%netscape.com Exp $
- */
- #include "nspr.h"
- #include "secutil.h"
- #include "plgetopt.h"
- #include "secpkcs7.h"
- #include "cert.h"
- #include "certdb.h"
- #include "cdbhdl.h"
- #include "secoid.h"
- #include "cms.h"
- #include "nss.h"
- #include "smime.h"
- #if defined(XP_UNIX)
- #include <unistd.h>
- #endif
- #include <stdio.h>
- #include <string.h>
- extern void SEC_Init(void); /* XXX */
- char *progName = NULL;
- static SECStatus
- DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,
- SECAlgorithmID **algids)
- {
- NSSCMSDigestContext *digcx;
- digcx = NSS_CMSDigestContext_StartMultiple(algids);
- if (digcx == NULL)
- return SECFailure;
- NSS_CMSDigestContext_Update(digcx, input->data, input->len);
- return NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);
- }
- static void
- Usage(char *progName)
- {
- fprintf(stderr, "Usage: %s [-D|-S|-E] [<options>] [-d dbdir] [-u certusage]n", progName);
- fprintf(stderr, " -i infile use infile as source of data (default: stdin)n");
- fprintf(stderr, " -o outfile use outfile as destination of data (default: stdout)n");
- fprintf(stderr, " -d dbdir key/cert database directory (default: ~/.netscape)n");
- fprintf(stderr, " -p password use password as key db password (default: prompt)n");
- fprintf(stderr, " -u certusage set type of certificate usage (default: certUsageEmailSigner)n");
- fprintf(stderr, "n");
- fprintf(stderr, " -D decode a CMS messagen");
- fprintf(stderr, " -c content use this detached contentn");
- fprintf(stderr, " -n suppress output of contentn");
- fprintf(stderr, " -h num generate email headers with info about CMS messagen");
- fprintf(stderr, " -S create a CMS signed messagen");
- fprintf(stderr, " -N nick use certificate named "nick" for signingn");
- fprintf(stderr, " -T do not include content in CMS messagen");
- fprintf(stderr, " -G include a signing time attributen");
- fprintf(stderr, " -P include a SMIMECapabilities attributen");
- fprintf(stderr, " -Y nick include a EncryptionKeyPreference attribute with certn");
- fprintf(stderr, " -E create a CMS enveloped message (NYI)n");
- fprintf(stderr, " -r id,... create envelope for these recipients,n");
- fprintf(stderr, " where id can be a certificate nickname or email addressn");
- fprintf(stderr, "nCert usage codes:n");
- fprintf(stderr, "%-25s 0 - certUsageSSLClientn", " ");
- fprintf(stderr, "%-25s 1 - certUsageSSLServern", " ");
- fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUpn", " ");
- fprintf(stderr, "%-25s 3 - certUsageSSLCAn", " ");
- fprintf(stderr, "%-25s 4 - certUsageEmailSignern", " ");
- fprintf(stderr, "%-25s 5 - certUsageEmailRecipientn", " ");
- fprintf(stderr, "%-25s 6 - certUsageObjectSignern", " ");
- fprintf(stderr, "%-25s 7 - certUsageUserCertImportn", " ");
- fprintf(stderr, "%-25s 8 - certUsageVerifyCAn", " ");
- fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSignern", " ");
- fprintf(stderr, "%-25s 10 - certUsageStatusRespondern", " ");
- fprintf(stderr, "%-25s 11 - certUsageAnyCAn", " ");
- exit(-1);
- }
- static CERTCertDBHandle certHandleStatic; /* avoid having to allocate */
- static CERTCertDBHandle *
- OpenCertDB(char *progName)
- {
- CERTCertDBHandle *certHandle;
- SECStatus rv;
- certHandle = &certHandleStatic;
- rv = CERT_OpenCertDB(certHandle, PR_FALSE, SECU_CertDBNameCallback, NULL);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "could not open cert database");
- return NULL;
- }
- return certHandle;
- }
- char *
- ownpw(PK11SlotInfo *info, PRBool retry, void *arg)
- {
- char * passwd = NULL;
- if ( (!retry) && arg ) {
- passwd = PL_strdup((char *)arg);
- }
- return passwd;
- }
- struct optionsStr {
- char *password;
- SECCertUsage certUsage;
- CERTCertDBHandle *certHandle;
- };
- struct decodeOptionsStr {
- struct optionsStr *options;
- PRFileDesc *contentFile;
- int headerLevel;
- PRBool suppressContent;
- NSSCMSGetDecryptKeyCallback dkcb;
- PK11SymKey *bulkkey;
- };
- struct signOptionsStr {
- struct optionsStr *options;
- char *nickname;
- char *encryptionKeyPreferenceNick;
- PRBool signingTime;
- PRBool smimeProfile;
- PRBool detached;
- };
- struct envelopeOptionsStr {
- struct optionsStr *options;
- char **recipients;
- };
- struct certsonlyOptionsStr {
- struct optionsStr *options;
- char **recipients;
- };
- struct encryptOptionsStr {
- struct optionsStr *options;
- char **recipients;
- NSSCMSMessage *envmsg;
- SECItem *input;
- FILE *outfile;
- PRFileDesc *envFile;
- PK11SymKey *bulkkey;
- SECOidTag bulkalgtag;
- int keysize;
- };
- static NSSCMSMessage *
- decode(FILE *out, SECItem *output, SECItem *input,
- struct decodeOptionsStr decodeOptions)
- {
- NSSCMSDecoderContext *dcx;
- NSSCMSMessage *cmsg;
- NSSCMSContentInfo *cinfo;
- NSSCMSSignedData *sigd = NULL;
- NSSCMSEnvelopedData *envd;
- NSSCMSEncryptedData *encd;
- SECAlgorithmID **digestalgs;
- int nlevels, i, nsigners, j;
- char *signercn;
- NSSCMSSignerInfo *si;
- SECOidTag typetag;
- SECItem **digests;
- PLArenaPool *poolp;
- PK11PasswordFunc pwcb;
- void *pwcb_arg;
- SECItem *item, sitem = { 0, 0, 0 };
- pwcb = (decodeOptions.options->password != NULL) ? ownpw : NULL;
- pwcb_arg = (decodeOptions.options->password != NULL) ?
- (void *)decodeOptions.options->password : NULL;
- if (decodeOptions.contentFile) {
- /* detached content: grab content file */
- SECU_FileToItem(&sitem, decodeOptions.contentFile);
- item = &sitem;
- }
- dcx = NSS_CMSDecoder_Start(NULL,
- NULL, NULL, /* content callback */
- pwcb, pwcb_arg, /* password callback */
- decodeOptions.dkcb, /* decrypt key callback */
- decodeOptions.bulkkey);
- (void)NSS_CMSDecoder_Update(dcx, input->data, input->len);
- cmsg = NSS_CMSDecoder_Finish(dcx);
- if (cmsg == NULL) {
- fprintf(stderr, "%s: failed to decode message.n", progName);
- return NULL;
- }
- if (decodeOptions.headerLevel >= 0) {
- /*fprintf(out, "SMIME: ", decodeOptions.headerLevel, i);*/
- fprintf(out, "SMIME: ");
- }
- nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);
- for (i = 0; i < nlevels; i++) {
- cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);
- typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "tlevel=%d.%d; ", decodeOptions.headerLevel, nlevels - i);
- switch (typetag) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "type=signedData; ");
- sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
- if (sigd == NULL) {
- SECU_PrintError(progName,
- "problem finding signedData component");
- goto loser;
- }
- /* if we have a content file, but no digests for this signedData */
- if (decodeOptions.contentFile != NULL && !NSS_CMSSignedData_HasDigests(sigd)) {
- if ((poolp = PORT_NewArena(1024)) == NULL) {
- fprintf(stderr, "cmsutil: Out of memory.n");
- goto loser;
- }
- digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);
- if (DigestFile (poolp, &digests, item, digestalgs)
- != SECSuccess) {
- SECU_PrintError(progName,
- "problem computing message digest");
- goto loser;
- }
- if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {
-
- SECU_PrintError(progName,
- "problem setting message digests");
- goto loser;
- }
- PORT_FreeArena(poolp, PR_FALSE);
- }
- /* import the certificates */
- if (NSS_CMSSignedData_ImportCerts(sigd,
- decodeOptions.options->certHandle,
- decodeOptions.options->certUsage,
- PR_FALSE)
- != SECSuccess) {
- SECU_PrintError(progName, "cert import failed");
- goto loser;
- }
- /* find out about signers */
- nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "nsigners=%d; ", nsigners);
- if (nsigners == 0) {
- /* must be a cert transport message */
- SECStatus rv;
- /* XXX workaround for bug #54014 */
- NSS_CMSSignedData_ImportCerts(sigd,
- decodeOptions.options->certHandle,
- decodeOptions.options->certUsage,
- PR_TRUE);
- rv = NSS_CMSSignedData_VerifyCertsOnly(sigd,
- decodeOptions.options->certHandle,
- decodeOptions.options->certUsage);
- if (rv != SECSuccess) {
- fprintf(stderr, "cmsutil: Verify certs-only failed!n");
- goto loser;
- }
- return cmsg;
- }
- /* still no digests? */
- if (!NSS_CMSSignedData_HasDigests(sigd)) {
- SECU_PrintError(progName, "no message digests");
- goto loser;
- }
- for (j = 0; j < nsigners; j++) {
- si = NSS_CMSSignedData_GetSignerInfo(sigd, j);
- signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);
- if (signercn == NULL)
- signercn = "";
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "nttsigner%d.id="%s"; ", j, signercn);
- (void)NSS_CMSSignedData_VerifySignerInfo(sigd, j,
- decodeOptions.options->certHandle,
- decodeOptions.options->certUsage);
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "signer%d.status=%s; ", j,
- NSS_CMSUtil_VerificationStatusToString(
- NSS_CMSSignerInfo_GetVerificationStatus(si)));
- /* XXX what do we do if we don't print headers? */
- }
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "type=envelopedData; ");
- envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "type=encryptedData; ");
- encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);
- break;
- case SEC_OID_PKCS7_DATA:
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "type=data; ");
- break;
- default:
- break;
- }
- if (decodeOptions.headerLevel >= 0)
- fprintf(out, "n");
- }
- if (!decodeOptions.suppressContent) {
- if (!decodeOptions.contentFile)
- item = NSS_CMSMessage_GetContent(cmsg);
- SECITEM_CopyItem(NULL, output, item);
- }
- return cmsg;
- loser:
- if (cmsg)
- NSS_CMSMessage_Destroy(cmsg);
- return NULL;
- }
- /* example of a callback function to use with encoder */
- /*
- static void
- writeout(void *arg, const char *buf, unsigned long len)
- {
- FILE *f = (FILE *)arg;
- if (f != NULL && buf != NULL)
- (void)fwrite(buf, len, 1, f);
- }
- */
- static NSSCMSMessage *
- signed_data(struct signOptionsStr signOptions)
- {
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSSignedData *sigd;
- NSSCMSSignerInfo *signerinfo;
- CERTCertificate *cert, *ekpcert;
- if (signOptions.nickname == NULL) {
- fprintf(stderr,
- "ERROR: please indicate the nickname of a certificate to sign with.n");
- return NULL;
- }
- if ((cert = CERT_FindCertByNickname(signOptions.options->certHandle,
- signOptions.nickname)) == NULL) {
- SECU_PrintError(progName,
- "the corresponding cert for key "%s" does not exist",
- signOptions.nickname);
- return NULL;
- }
- /*
- * create the message object
- */
- cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
- if (cmsg == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS message.n");
- return NULL;
- }
- /*
- * build chain of objects: message->signedData->data
- */
- if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS signedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
- if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS signedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
- /* we're always passing data in and detaching optionally */
- if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL,
- signOptions.detached)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS data object.n");
- goto loser;
- }
- /*
- * create & attach signer information
- */
- if ((signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, SEC_OID_SHA1))
- == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS signerInfo object.n");
- goto loser;
- }
- /* we want the cert chain included for this one */
- if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain,
- signOptions.options->certUsage)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot find cert chain.n");
- goto loser;
- }
- if (signOptions.signingTime) {
- if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now())
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add signingTime attribute.n");
- goto loser;
- }
- }
- if (signOptions.smimeProfile) {
- if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.n");
- goto loser;
- }
- }
- if (signOptions.encryptionKeyPreferenceNick) {
- /* get the cert, add it to the message */
- if ((ekpcert = CERT_FindCertByNickname(signOptions.options->certHandle,
- signOptions.encryptionKeyPreferenceNick))
- == NULL) {
- SECU_PrintError(progName,
- "the corresponding cert for key "%s" does not exist",
- signOptions.encryptionKeyPreferenceNick);
- goto loser;
- }
- if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert,
- signOptions.options->certHandle)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.n");
- goto loser;
- }
- if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add encryption certificate.n");
- goto loser;
- }
- } else {
- /* check signing cert for fitness as encryption cert */
- /* if yes, add signing cert as EncryptionKeyPreference */
- if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert,
- signOptions.options->certHandle)
- != SECSuccess) {
- fprintf(stderr,
- "ERROR: cannot add default SMIMEEncKeyPrefs attribute.n");
- goto loser;
- }
- }
- if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add CMS signerInfo object.n");
- goto loser;
- }
- return cmsg;
- loser:
- NSS_CMSMessage_Destroy(cmsg);
- return NULL;
- }
- static NSSCMSMessage *
- enveloped_data(struct envelopeOptionsStr envelopeOptions)
- {
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSEnvelopedData *envd;
- NSSCMSRecipientInfo *recipientinfo;
- CERTCertificate **recipientcerts;
- CERTCertDBHandle *dbhandle;
- PLArenaPool *tmppoolp = NULL;
- SECOidTag bulkalgtag;
- int keysize, i;
- int cnt;
- dbhandle = envelopeOptions.options->certHandle;
- /* count the recipients */
- if ((cnt = NSS_CMSArray_Count(envelopeOptions.recipients)) == 0) {
- fprintf(stderr, "ERROR: please name at least one recipient.n");
- goto loser;
- }
- if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
- fprintf(stderr, "ERROR: out of memory.n");
- goto loser;
- }
- /* XXX find the recipient's certs by email address or nickname */
- if ((recipientcerts =
- (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp,
- (cnt+1)*sizeof(CERTCertificate*)))
- == NULL) {
- fprintf(stderr, "ERROR: out of memory.n");
- goto loser;
- }
- for (i=0; envelopeOptions.recipients[i] != NULL; i++) {
- if ((recipientcerts[i] =
- CERT_FindCertByNicknameOrEmailAddr(dbhandle,
- envelopeOptions.recipients[i]))
- == NULL) {
- SECU_PrintError(progName, "cannot find certificate for "%s"",
- envelopeOptions.recipients[i]);
- goto loser;
- }
- }
- recipientcerts[i] = NULL;
- /* find a nice bulk algorithm */
- if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag,
- &keysize) != SECSuccess) {
- fprintf(stderr, "ERROR: cannot find common bulk algorithm.n");
- goto loser;
- }
- /*
- * create the message object
- */
- cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
- if (cmsg == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS message.n");
- goto loser;
- }
- /*
- * build chain of objects: message->envelopedData->data
- */
- if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize))
- == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS envelopedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
- if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
- /* we're always passing data in, so the content is NULL */
- if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS data object.n");
- goto loser;
- }
- /*
- * create & attach recipient information
- */
- for (i = 0; recipientcerts[i] != NULL; i++) {
- if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg,
- recipientcerts[i]))
- == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.n");
- goto loser;
- }
- if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.n");
- goto loser;
- }
- }
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- return cmsg;
- loser:
- if (cmsg)
- NSS_CMSMessage_Destroy(cmsg);
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- return NULL;
- }
- PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid)
- {
- return (PK11SymKey*)arg;
- }
- static SECStatus
- get_enc_params(struct encryptOptionsStr *encryptOptions)
- {
- struct envelopeOptionsStr envelopeOptions;
- SECStatus rv = SECFailure;
- NSSCMSMessage *env_cmsg;
- NSSCMSContentInfo *cinfo;
- PK11SymKey *bulkkey = NULL;
- SECOidTag bulkalgtag;
- int keysize;
- int i, nlevels;
- /*
- * construct an enveloped data message to obtain bulk keys
- */
- if (encryptOptions->envmsg) {
- env_cmsg = encryptOptions->envmsg; /* get it from an old message */
- } else {
- SECItem dummyOut = { 0, 0, 0 };
- SECItem dummyIn = { 0, 0, 0 };
- char str[] = "Hello!";
- PLArenaPool *tmparena = PORT_NewArena(1024);
- dummyIn.data = str;
- dummyIn.len = strlen(str);
- envelopeOptions.options = encryptOptions->options;
- envelopeOptions.recipients = encryptOptions->recipients;
- env_cmsg = enveloped_data(envelopeOptions);
- NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena);
- PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len);
- PORT_FreeArena(tmparena, PR_FALSE);
- }
- /*
- * get the content info for the enveloped data
- */
- nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg);
- for (i = 0; i < nlevels; i++) {
- SECOidTag typetag;
- cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i);
- typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
- if (typetag == SEC_OID_PKCS7_DATA) {
- /*
- * get the symmetric key
- */
- bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
- keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo);
- bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
- break;
- }
- }
- if (i == nlevels) {
- fprintf(stderr, "%s: could not retrieve enveloped data.", progName);
- goto loser;
- }
- encryptOptions->bulkalgtag = bulkalgtag;
- encryptOptions->bulkkey = bulkkey;
- encryptOptions->keysize = keysize;
- rv = SECSuccess;
- loser:
- if (env_cmsg)
- NSS_CMSMessage_Destroy(env_cmsg);
- return rv;
- }
- static NSSCMSMessage *
- encrypted_data(struct encryptOptionsStr encryptOptions)
- {
- SECStatus rv = SECFailure;
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSEncryptedData *encd;
- NSSCMSEncoderContext *ecx = NULL;
- PLArenaPool *tmppoolp = NULL;
- SECItem derOut = { 0, 0, 0 };
- /* arena for output */
- tmppoolp = PORT_NewArena(1024);
- if (!tmppoolp) {
- fprintf(stderr, "%s: out of memory.n", progName);
- return NULL;
- }
- /*
- * create the message object
- */
- cmsg = NSS_CMSMessage_Create(NULL);
- if (cmsg == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS message.n");
- goto loser;
- }
- /*
- * build chain of objects: message->encryptedData->data
- */
- if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions.bulkalgtag,
- encryptOptions.keysize))
- == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS encryptedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
- if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSEncryptedData_GetContentInfo(encd);
- /* we're always passing data in, so the content is NULL */
- if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS data object.n");
- goto loser;
- }
- ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL,
- dkcb, encryptOptions.bulkkey, NULL, NULL);
- if (!ecx) {
- fprintf(stderr, "%s: cannot create encoder context.n", progName);
- goto loser;
- }
- rv = NSS_CMSEncoder_Update(ecx, encryptOptions.input->data,
- encryptOptions.input->len);
- if (rv) {
- fprintf(stderr, "%s: failed to add data to encoder.n", progName);
- goto loser;
- }
- rv = NSS_CMSEncoder_Finish(ecx);
- if (rv) {
- fprintf(stderr, "%s: failed to encrypt data.n", progName);
- goto loser;
- }
- fwrite(derOut.data, derOut.len, 1, encryptOptions.outfile);
- /*
- if (bulkkey)
- PK11_FreeSymKey(bulkkey);
- */
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- return cmsg;
- loser:
- /*
- if (bulkkey)
- PK11_FreeSymKey(bulkkey);
- */
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- if (cmsg)
- NSS_CMSMessage_Destroy(cmsg);
- return NULL;
- }
- static NSSCMSMessage *
- signed_data_certsonly(struct certsonlyOptionsStr certsonlyOptions)
- {
- NSSCMSMessage *cmsg = NULL;
- NSSCMSContentInfo *cinfo;
- NSSCMSSignedData *sigd;
- CERTCertificate **certs;
- CERTCertDBHandle *dbhandle;
- PLArenaPool *tmppoolp = NULL;
- int i, cnt;
- dbhandle = certsonlyOptions.options->certHandle;
- if ((cnt = NSS_CMSArray_Count(certsonlyOptions.recipients)) == 0) {
- fprintf(stderr,
- "ERROR: please indicate the nickname of a certificate to sign with.n");
- goto loser;
- }
- if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
- fprintf(stderr, "ERROR: out of memory.n");
- goto loser;
- }
- if ((certs =
- (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp,
- (cnt+1)*sizeof(CERTCertificate*)))
- == NULL) {
- fprintf(stderr, "ERROR: out of memory.n");
- goto loser;
- }
- for (i=0; certsonlyOptions.recipients[i] != NULL; i++) {
- if ((certs[i] =
- CERT_FindCertByNicknameOrEmailAddr(dbhandle,
- certsonlyOptions.recipients[i]))
- == NULL) {
- SECU_PrintError(progName, "cannot find certificate for "%s"",
- certsonlyOptions.recipients[i]);
- goto loser;
- }
- }
- certs[i] = NULL;
- /*
- * create the message object
- */
- cmsg = NSS_CMSMessage_Create(NULL);
- if (cmsg == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS message.n");
- goto loser;
- }
- /*
- * build chain of objects: message->signedData->data
- */
- if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE))
- == NULL) {
- fprintf(stderr, "ERROR: cannot create CMS signedData object.n");
- goto loser;
- }
- for (i=1; i<cnt; i++) {
- if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) {
- fprintf(stderr, "ERROR: cannot add cert chain for "%s".n",
- certsonlyOptions.recipients[i]);
- goto loser;
- }
- }
- cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
- if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS signedData object.n");
- goto loser;
- }
- cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
- if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE)
- != SECSuccess) {
- fprintf(stderr, "ERROR: cannot attach CMS data object.n");
- goto loser;
- }
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- return cmsg;
- loser:
- if (cmsg)
- NSS_CMSMessage_Destroy(cmsg);
- if (tmppoolp)
- PORT_FreeArena(tmppoolp, PR_FALSE);
- return NULL;
- }
- typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode;
- #if 0
- void
- parse_message_for_recipients(PRFileDesc *inFile,
- struct envelopeOptionsStr *envelopeOptions)
- {
- SECItem filedata;
- SECStatus rv;
- rv = SECU_FileToItem(&filedata, inFile);
- }
- #endif
- int
- main(int argc, char **argv)
- {
- FILE *outFile;
- NSSCMSMessage *cmsg;
- PRFileDesc *inFile;
- PLOptState *optstate;
- PLOptStatus status;
- Mode mode = UNKNOWN;
- PK11PasswordFunc pwcb;
- void *pwcb_arg;
- struct decodeOptionsStr decodeOptions = { 0 };
- struct signOptionsStr signOptions = { 0 };
- struct envelopeOptionsStr envelopeOptions = { 0 };
- struct certsonlyOptionsStr certsonlyOptions = { 0 };
- struct encryptOptionsStr encryptOptions = { 0 };
- struct optionsStr options = { 0 };
- int exitstatus;
- static char *ptrarray[128] = { 0 };
- int nrecipients = 0;
- char *str, *tok;
- char *envFileName;
- SECItem input = { 0, 0, 0};
- SECItem output = { 0, 0, 0};
- SECItem dummy = { 0, 0, 0 };
- SECItem envmsg = { 0, 0, 0 };
- SECStatus rv;
- progName = strrchr(argv[0], '/');
- progName = progName ? progName+1 : argv[0];
- inFile = PR_STDIN;
- outFile = stdout;
- envFileName = NULL;
- mode = UNKNOWN;
- decodeOptions.contentFile = NULL;
- decodeOptions.suppressContent = PR_FALSE;
- decodeOptions.headerLevel = -1;
- options.certUsage = certUsageEmailSigner;
- options.password = NULL;
- signOptions.nickname = NULL;
- signOptions.detached = PR_FALSE;
- signOptions.signingTime = PR_FALSE;
- signOptions.smimeProfile = PR_FALSE;
- signOptions.encryptionKeyPreferenceNick = NULL;
- envelopeOptions.recipients = NULL;
- encryptOptions.recipients = NULL;
- encryptOptions.envmsg = NULL;
- encryptOptions.envFile = NULL;
- encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;
- encryptOptions.bulkkey = NULL;
- encryptOptions.keysize = -1;
- /*
- * Parse command line arguments
- */
- optstate = PL_CreateOptState(argc, argv,
- "CDSEOnN:TGPY:h:p:i:c:d:e:o:s:u:r:");
- while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
- switch (optstate->option) {
- case '?':
- Usage(progName);
- break;
-
- case 'C':
- mode = ENCRYPT;
- break;
- case 'D':
- mode = DECODE;
- break;
- case 'S':
- mode = SIGN;
- break;
- case 'E':
- mode = ENVELOPE;
- break;
- case 'O':
- mode = CERTSONLY;
- break;
- case 'n':
- if (mode != DECODE) {
- fprintf(stderr,
- "%s: option -n only supported with option -D.n",
- progName);
- Usage(progName);
- exit(1);
- }
- decodeOptions.suppressContent = PR_TRUE;
- break;
- case 'N':
- if (mode != SIGN) {
- fprintf(stderr,
- "%s: option -N only supported with option -S.n",
- progName);
- Usage(progName);
- exit(1);
- }
- signOptions.nickname = strdup(optstate->value);
- break;
- case 'Y':
- if (mode != SIGN) {
- fprintf(stderr,
- "%s: option -Y only supported with option -S.n",
- progName);
- Usage(progName);
- exit(1);
- }
- signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);
- break;
- case 'T':
- if (mode != SIGN) {
- fprintf(stderr,
- "%s: option -T only supported with option -S.n",
- progName);
- Usage(progName);
- exit(1);
- }
- signOptions.detached = PR_TRUE;
- break;
- case 'G':
- if (mode != SIGN) {
- fprintf(stderr,
- "%s: option -G only supported with option -S.n",
- progName);
- Usage(progName);
- exit(1);
- }
- signOptions.signingTime = PR_TRUE;
- break;
- case 'P':
- if (mode != SIGN) {
- fprintf(stderr,
- "%s: option -P only supported with option -S.n",
- progName);
- Usage(progName);
- exit(1);
- }
- signOptions.smimeProfile = PR_TRUE;
- break;
- case 'h':
- if (mode != DECODE) {
- fprintf(stderr,
- "%s: option -h only supported with option -D.n",
- progName);
- Usage(progName);
- exit(1);
- }
- decodeOptions.headerLevel = atoi(optstate->value);
- if (decodeOptions.headerLevel < 0) {
- fprintf(stderr, "option -h cannot have a negative value.n");
- exit(1);
- }
- break;
- case 'p':
- if (!optstate->value) {
- fprintf(stderr, "%s: option -p must have a value.n", progName);
- Usage(progName);
- exit(1);
- }
-
- options.password = strdup(optstate->value);
- break;
- case 'i':
- inFile = PR_Open(optstate->value, PR_RDONLY, 00660);
- if (inFile == NULL) {
- fprintf(stderr, "%s: unable to open "%s" for readingn",
- progName, optstate->value);
- exit(1);
- }
- SECU_FileToItem(&input, inFile);
- PR_Close(inFile);
- break;
- case 'c':
- if (mode != DECODE) {
- fprintf(stderr,
- "%s: option -c only supported with option -D.n",
- progName);
- Usage(progName);
- exit(1);
- }
- if ((decodeOptions.contentFile =
- PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) {
- fprintf(stderr, "%s: unable to open "%s" for reading.n",
- progName, optstate->value);
- exit(1);
- }
- break;
- case 'o':
- #if 0
- if (mode == DECODE) {
- outFile = fopen(optstate->value, "w");
- } else {
- outFile = fopen(optstate->value, "wb");
- }
- #endif
- outFile = fopen(optstate->value, "wb");
- if (outFile == NULL) {
- fprintf(stderr, "%s: unable to open "%s" for writingn",
- progName, optstate->value);
- exit(1);
- }
- break;
- case 'r':
- if (!optstate->value) {
- fprintf(stderr, "%s: option -r must have a value.n", progName);
- Usage(progName);
- exit(1);
- }
- #if 0
- fprintf(stderr, "recipient = %sn", optstate->value);
- #endif
- envelopeOptions.recipients = ptrarray;
- str = optstate->value;
- do {
- tok = strchr(str, ',');
- if (tok) *tok = ' ';
- envelopeOptions.recipients[nrecipients++] = strdup(str);
- if (tok) str = tok + 1;
- } while (tok);
- envelopeOptions.recipients[nrecipients] = NULL;
- encryptOptions.recipients = envelopeOptions.recipients;
- certsonlyOptions.recipients = envelopeOptions.recipients;
- break;
- case 'd':
- SECU_ConfigDirectory(optstate->value);
- break;
- case 'e':
- envFileName = strdup(optstate->value);
- encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);
- break;
- case 'u': {
- int usageType;
- usageType = atoi (strdup(optstate->value));
- if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)
- return -1;
- options.certUsage = (SECCertUsage)usageType;
- break;
- }
-
- }
- }
- /* Call the libsec initialization routines */
- PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
- rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));
- if (SECSuccess != rv) {
- SECU_PrintError(progName, "NSS_Init failed");
- exit(1);
- }
- options.certHandle = CERT_GetDefaultCertDB();
- if (!options.certHandle) {
- SECU_PrintError(progName, "No default cert DB");
- exit(1);
- }
- #if defined(WIN32)
- /*if (outFile == stdout && mode != DECODE) {*/
- if (outFile == stdout) {
- /* If we're going to write binary data to stdout, we must put stdout
- ** into O_BINARY mode or else outgoing n's will become rn's.
- */
- int smrv = _setmode(_fileno(stdout), _O_BINARY);
- if (smrv == -1) {
- fprintf(stderr,
- "%s: Cannot change stdout to binary mode. Use -o option instead.n",
- progName);
- return smrv;
- }
- }
- #endif
- exitstatus = 0;
- switch (mode) {
- case DECODE:
- decodeOptions.options = &options;
- if (encryptOptions.envFile) {
- /* Decoding encrypted-data, so get the bulkkey from an
- * enveloped-data message.
- */
- SECU_FileToItem(&envmsg, encryptOptions.envFile);
- decodeOptions.options = &options;
- encryptOptions.envmsg = decode(NULL, &dummy, &envmsg,
- decodeOptions);
- rv = get_enc_params(&encryptOptions);
- decodeOptions.dkcb = dkcb;
- decodeOptions.bulkkey = encryptOptions.bulkkey;
- }
- cmsg = decode(outFile, &output, &input, decodeOptions);
- if (!cmsg) {
- SECU_PrintError(progName, "problem decoding");
- exitstatus = 1;
- }
- fwrite(output.data, output.len, 1, outFile);
- break;
- case SIGN:
- signOptions.options = &options;
- cmsg = signed_data(signOptions);
- if (!cmsg) {
- SECU_PrintError(progName, "problem signing");
- exitstatus = 1;
- }
- break;
- case ENCRYPT:
- if (!envFileName) {
- fprintf(stderr, "%s: you must specify an envelope file with -e.n",
- progName);
- exit(1);
- }
- encryptOptions.options = &options;
- encryptOptions.input = &input;
- encryptOptions.outfile = outFile;
- if (!encryptOptions.envFile) {
- encryptOptions.envFile = PR_Open(envFileName,
- PR_WRONLY|PR_CREATE_FILE, 00660);
- if (!encryptOptions.envFile) {
- fprintf(stderr, "%s: failed to create file %s.n", progName,
- envFileName);
- exit(1);
- }
- } else {
- SECU_FileToItem(&envmsg, encryptOptions.envFile);
- decodeOptions.options = &options;
- encryptOptions.envmsg = decode(NULL, &dummy, &envmsg,
- decodeOptions);
- }
- /* decode an enveloped-data message to get the bulkkey (create
- * a new one if neccessary)
- */
- rv = get_enc_params(&encryptOptions);
- /* create the encrypted-data message */
- cmsg = encrypted_data(encryptOptions);
- if (!cmsg) {
- SECU_PrintError(progName, "problem encrypting");
- exitstatus = 1;
- }
- break;
- case ENVELOPE:
- envelopeOptions.options = &options;
- #if 0
- if (!envelopeOptions.recipients)
- parse_message_for_recipients(myIn, &envelopeOptions);
- #endif
- cmsg = enveloped_data(envelopeOptions);
- if (!cmsg) {
- SECU_PrintError(progName, "problem enveloping");
- exitstatus = 1;
- }
- break;
- case CERTSONLY:
- certsonlyOptions.options = &options;
- cmsg = signed_data_certsonly(certsonlyOptions);
- if (!cmsg) {
- SECU_PrintError(progName, "problem with certs-only");
- exitstatus = 1;
- }
- break;
- default:
- fprintf(stderr, "One of options -D, -S or -E must be set.n");
- Usage(progName);
- exitstatus = 1;
- }
- if (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY) {
- PLArenaPool *arena = PORT_NewArena(1024);
- NSSCMSEncoderContext *ecx;
- SECItem output = { 0, 0, 0 };
- if (!arena) {
- fprintf(stderr, "%s: out of memory.n", progName);
- exit(1);
- }
- pwcb = (options.password != NULL) ? ownpw : NULL;
- pwcb_arg = (options.password != NULL) ? (void *)options.password : NULL;
- ecx = NSS_CMSEncoder_Start(cmsg,
- NULL, NULL, /* DER output callback */
- &output, arena, /* destination storage */
- pwcb, pwcb_arg, /* password callback */
- NULL, NULL, /* decrypt key callback */
- NULL, NULL ); /* detached digests */
- if (!ecx) {
- fprintf(stderr, "%s: cannot create encoder context.n", progName);
- exit(1);
- }
- if (input.len > 0) { /* skip if certs-only (or other zero content) */
- rv = NSS_CMSEncoder_Update(ecx, input.data, input.len);
- if (rv) {
- fprintf(stderr,
- "%s: failed to add data to encoder.n", progName);
- exit(1);
- }
- }
- rv = NSS_CMSEncoder_Finish(ecx);
- if (rv) {
- fprintf(stderr, "%s: failed to encode data.n", progName);
- exit(1);
- }
- /*PR_Write(output.data, output.len);*/
- fwrite(output.data, output.len, 1, outFile);
- PORT_FreeArena(arena, PR_FALSE);
- }
- if (cmsg)
- NSS_CMSMessage_Destroy(cmsg);
- if (outFile != stdout)
- fclose(outFile);
- if (decodeOptions.contentFile)
- PR_Close(decodeOptions.contentFile);
- exit(exitstatus);
- }