diff options
Diffstat (limited to 'security/nss/cmd/smimetools')
-rw-r--r-- | security/nss/cmd/smimetools/Makefile | 81 | ||||
-rw-r--r-- | security/nss/cmd/smimetools/cmsutil.c | 1651 | ||||
-rw-r--r-- | security/nss/cmd/smimetools/manifest.mn | 49 | ||||
-rw-r--r-- | security/nss/cmd/smimetools/rules.mk | 40 | ||||
-rwxr-xr-x | security/nss/cmd/smimetools/smime | 581 |
5 files changed, 0 insertions, 2402 deletions
diff --git a/security/nss/cmd/smimetools/Makefile b/security/nss/cmd/smimetools/Makefile deleted file mode 100644 index 2d4665b18..000000000 --- a/security/nss/cmd/smimetools/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -#! gmake -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# 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 the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -####################################################################### -# (1) Include initial platform-independent assignments (MANDATORY). # -####################################################################### - -include manifest.mn - -####################################################################### -# (2) Include "global" configuration information. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/config.mk - -####################################################################### -# (3) Include "component" configuration information. (OPTIONAL) # -####################################################################### - -####################################################################### -# (4) Include "local" platform-dependent assignments (OPTIONAL). # -####################################################################### - -include ../platlibs.mk - -ifdef NISCC_TEST -DEFINES += -DNISCC_TEST -endif - -####################################################################### -# (5) Execute "global" rules. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/rules.mk - -####################################################################### -# (6) Execute "component" rules. (OPTIONAL) # -####################################################################### - -####################################################################### -# (7) Execute "local" rules. (OPTIONAL). # -####################################################################### - -include rules.mk - -include ../platrules.mk diff --git a/security/nss/cmd/smimetools/cmsutil.c b/security/nss/cmd/smimetools/cmsutil.c deleted file mode 100644 index 19218456d..000000000 --- a/security/nss/cmd/smimetools/cmsutil.c +++ /dev/null @@ -1,1651 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * 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 the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * cmsutil -- A command to work with CMS data - * - * $Id$ - */ - -#include "nspr.h" -#include "secutil.h" -#include "plgetopt.h" -#include "secpkcs7.h" -#include "cert.h" -#include "certdb.h" -#include "secoid.h" -#include "cms.h" -#include "nss.h" -#include "smime.h" -#include "pk11func.h" - -#if defined(XP_UNIX) -#include <unistd.h> -#endif - -#if defined(_WIN32) -#include "fcntl.h" -#include "io.h" -#endif - -#include <stdio.h> -#include <string.h> - -char *progName = NULL; -static int cms_verbose = 0; -static secuPWData pwdata = { PW_NONE, 0 }; -static PK11PasswordFunc pwcb = NULL; -static void *pwcb_arg = NULL; - - -/* XXX stolen from cmsarray.c - * nss_CMSArray_Count - count number of elements in array - */ -int -nss_CMSArray_Count(void **array) -{ - int n = 0; - if (array == NULL) - return 0; - while (*array++ != NULL) - n++; - return n; -} - -static SECStatus -DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input, - SECAlgorithmID **algids) -{ - NSSCMSDigestContext *digcx; - SECStatus rv; - - digcx = NSS_CMSDigestContext_StartMultiple(algids); - if (digcx == NULL) - return SECFailure; - - NSS_CMSDigestContext_Update(digcx, input->data, input->len); - - rv = NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests); - return rv; -} - - -static void -Usage(char *progName) -{ - fprintf(stderr, -"Usage: %s [-C|-D|-E|-O|-S] [<options>] [-d dbdir] [-u certusage]\n" -" -C create a CMS encrypted data message\n" -" -D decode a CMS message\n" -" -b decode a batch of files named in infile\n" -" -c content use this detached content\n" -" -n suppress output of content\n" -" -h num display num levels of CMS message info as email headers\n" -" -k keep decoded encryption certs in perm cert db\n" -" -E create a CMS enveloped data message\n" -" -r id,... create envelope for these recipients,\n" -" where id can be a certificate nickname or email address\n" -" -S create a CMS signed data message\n" -" -G include a signing time attribute\n" -" -H hash use hash (default:SHA1)\n" -" -N nick use certificate named \"nick\" for signing\n" -" -P include a SMIMECapabilities attribute\n" -" -T do not include content in CMS message\n" -" -Y nick include a EncryptionKeyPreference attribute with cert\n" -" (use \"NONE\" to omit)\n" -" -O create a CMS signed message containing only certificates\n" -" General Options:\n" -" -d dbdir key/cert database directory (default: ~/.netscape)\n" -" -e envelope enveloped data message in this file is used for bulk key\n" -" -i infile use infile as source of data (default: stdin)\n" -" -o outfile use outfile as destination of data (default: stdout)\n" -" -p password use password as key db password (default: prompt)\n" -" -f pwfile use password file to set password on all PKCS#11 tokens)\n" -" -u certusage set type of certificate usage (default: certUsageEmailSigner)\n" -" -v print debugging information\n" -"\n" -"Cert usage codes:\n", - progName); - fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " "); - fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " "); - fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " "); - fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " "); - fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " "); - fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " "); - fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " "); - fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " "); - fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " "); - fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " "); - fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " "); - fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " "); - - exit(-1); -} - -struct optionsStr { - char *pwfile; - char *password; - SECCertUsage certUsage; - CERTCertDBHandle *certHandle; -}; - -struct decodeOptionsStr { - struct optionsStr *options; - SECItem content; - int headerLevel; - PRBool suppressContent; - NSSCMSGetDecryptKeyCallback dkcb; - PK11SymKey *bulkkey; - PRBool keepCerts; -}; - -struct signOptionsStr { - struct optionsStr *options; - char *nickname; - char *encryptionKeyPreferenceNick; - PRBool signingTime; - PRBool smimeProfile; - PRBool detached; - SECOidTag hashAlgTag; -}; - -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 *input, const struct decodeOptionsStr *decodeOptions) -{ - NSSCMSDecoderContext *dcx; - SECStatus rv; - NSSCMSMessage *cmsg; - int nlevels, i; - SECItem sitem = { 0, 0, 0 }; - - PORT_SetError(0); - dcx = NSS_CMSDecoder_Start(NULL, - NULL, NULL, /* content callback */ - pwcb, pwcb_arg, /* password callback */ - decodeOptions->dkcb, /* decrypt key callback */ - decodeOptions->bulkkey); - if (dcx == NULL) { - fprintf(stderr, "%s: failed to set up message decoder.\n", progName); - return NULL; - } - rv = NSS_CMSDecoder_Update(dcx, (char *)input->data, input->len); - if (rv != SECSuccess) { - fprintf(stderr, "%s: failed to decode message.\n", progName); - NSS_CMSDecoder_Cancel(dcx); - return NULL; - } - 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++) { - NSSCMSContentInfo *cinfo; - SECOidTag typetag; - - 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: - { - NSSCMSSignedData *sigd = NULL; - SECItem **digests; - int nsigners; - int j; - - if (decodeOptions->headerLevel >= 0) - fprintf(out, "type=signedData; "); - sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); - if (sigd == NULL) { - SECU_PrintError(progName, "signedData component missing"); - goto loser; - } - - /* if we have a content file, but no digests for this signedData */ - if (decodeOptions->content.data != NULL && - !NSS_CMSSignedData_HasDigests(sigd)) { - PLArenaPool *poolp; - SECAlgorithmID **digestalgs; - - /* detached content: grab content file */ - sitem = decodeOptions->content; - - if ((poolp = PORT_NewArena(1024)) == NULL) { - fprintf(stderr, "cmsutil: Out of memory.\n"); - goto loser; - } - digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd); - if (DigestFile (poolp, &digests, &sitem, digestalgs) - != SECSuccess) { - SECU_PrintError(progName, - "problem computing message digest"); - PORT_FreeArena(poolp, PR_FALSE); - goto loser; - } - if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) - != SECSuccess) { - SECU_PrintError(progName, - "problem setting message digests"); - PORT_FreeArena(poolp, PR_FALSE); - goto loser; - } - PORT_FreeArena(poolp, PR_FALSE); - } - - /* import the certificates */ - if (NSS_CMSSignedData_ImportCerts(sigd, - decodeOptions->options->certHandle, - decodeOptions->options->certUsage, - decodeOptions->keepCerts) - != 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) { - /* Might be a cert transport message - ** or might be an invalid message, such as a QA test message - ** or a message from an attacker. - */ - SECStatus rv; - 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++) { - const char * svs; - NSSCMSSignerInfo *si; - NSSCMSVerificationStatus vs; - SECStatus bad; - - si = NSS_CMSSignedData_GetSignerInfo(sigd, j); - if (decodeOptions->headerLevel >= 0) { - char *signercn; - static char empty[] = { "" }; - - signercn = NSS_CMSSignerInfo_GetSignerCommonName(si); - if (signercn == NULL) - signercn = empty; - fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn); - if (signercn != empty) - PORT_Free(signercn); - } - bad = NSS_CMSSignedData_VerifySignerInfo(sigd, j, - decodeOptions->options->certHandle, - decodeOptions->options->certUsage); - vs = NSS_CMSSignerInfo_GetVerificationStatus(si); - svs = NSS_CMSUtil_VerificationStatusToString(vs); - if (decodeOptions->headerLevel >= 0) { - fprintf(out, "signer%d.status=%s; ", j, svs); - /* goto loser ? */ - } else if (bad && out) { - fprintf(stderr, "signer %d status = %s\n", j, svs); - goto loser; - } - } - } - break; - case SEC_OID_PKCS7_ENVELOPED_DATA: - { - NSSCMSEnvelopedData *envd; - if (decodeOptions->headerLevel >= 0) - fprintf(out, "type=envelopedData; "); - envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); - if (envd == NULL) { - SECU_PrintError(progName, "envelopedData component missing"); - goto loser; - } - } - break; - case SEC_OID_PKCS7_ENCRYPTED_DATA: - { - NSSCMSEncryptedData *encd; - if (decodeOptions->headerLevel >= 0) - fprintf(out, "type=encryptedData; "); - encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); - if (encd == NULL) { - SECU_PrintError(progName, "encryptedData component missing"); - goto loser; - } - } - 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 && out) { - SECItem *item = (sitem.data ? &sitem - : NSS_CMSMessage_GetContent(cmsg)); - if (item && item->data && item->len) { - fwrite(item->data, item->len, 1, out); - } - } - 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= NULL, *ekpcert = NULL; - - if (cms_verbose) { - fprintf(stderr, "Input to signed_data:\n"); - if (signOptions->options->password) - fprintf(stderr, "password [%s]\n", signOptions->options->password); - else if (signOptions->options->pwfile) - fprintf(stderr, "password file [%s]\n", signOptions->options->pwfile); - else - fprintf(stderr, "password [NULL]\n"); - fprintf(stderr, "certUsage [%d]\n", signOptions->options->certUsage); - if (signOptions->options->certHandle) - fprintf(stderr, "certdb [%p]\n", signOptions->options->certHandle); - else - fprintf(stderr, "certdb [NULL]\n"); - if (signOptions->nickname) - fprintf(stderr, "nickname [%s]\n", signOptions->nickname); - else - fprintf(stderr, "nickname [NULL]\n"); - } - if (signOptions->nickname == NULL) { - fprintf(stderr, - "ERROR: please indicate the nickname of a certificate to sign with.\n"); - return NULL; - } - if ((cert = CERT_FindUserCertByUsage(signOptions->options->certHandle, - signOptions->nickname, - signOptions->options->certUsage, - PR_FALSE, - &pwdata)) == NULL) { - SECU_PrintError(progName, - "the corresponding cert for key \"%s\" does not exist", - signOptions->nickname); - return NULL; - } - if (cms_verbose) { - fprintf(stderr, "Found certificate for %s\n", signOptions->nickname); - } - /* - * 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 - */ - signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, signOptions->hashAlgTag); - if (signerinfo == NULL) { - fprintf(stderr, "ERROR: cannot create CMS signerInfo object.\n"); - goto loser; - } - if (cms_verbose) { - fprintf(stderr, - "Created CMS message, added signed data w/ signerinfo\n"); - } - /* 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 (cms_verbose) { - fprintf(stderr, "imported certificate\n"); - } - 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) { - /* check signing cert for fitness as encryption cert */ - SECStatus FitForEncrypt = CERT_CheckCertUsage(cert, - certUsageEmailRecipient); - - if (SECSuccess == FitForEncrypt) { - /* 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_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, cert, - signOptions->options->certHandle) - != SECSuccess) { - fprintf(stderr, - "ERROR: cannot add default MS SMIMEEncKeyPrefs attribute.\n"); - goto loser; - } - } else { - /* this is a dual-key cert case, we need to look for the encryption - certificate under the same nickname as the signing cert */ - /* get the cert, add it to the message */ - if ((ekpcert = CERT_FindUserCertByUsage( - signOptions->options->certHandle, - signOptions->nickname, - certUsageEmailRecipient, - PR_FALSE, - &pwdata)) == 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_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, - signOptions->options->certHandle) - != SECSuccess) { - fprintf(stderr, - "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n"); - goto loser; - } - if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) { - fprintf(stderr, "ERROR: cannot add encryption certificate.\n"); - goto loser; - } - } - } else if (PL_strcmp(signOptions->encryptionKeyPreferenceNick, "NONE") == 0) { - /* No action */ - } else { - /* get the cert, add it to the message */ - if ((ekpcert = CERT_FindUserCertByUsage( - signOptions->options->certHandle, - signOptions->encryptionKeyPreferenceNick, - certUsageEmailRecipient, PR_FALSE, &pwdata)) - == 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_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, - signOptions->options->certHandle) - != SECSuccess) { - fprintf(stderr, "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n"); - goto loser; - } - if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) { - fprintf(stderr, "ERROR: cannot add encryption certificate.\n"); - goto loser; - } - } - - if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { - fprintf(stderr, "ERROR: cannot add CMS signerInfo object.\n"); - goto loser; - } - if (cms_verbose) { - fprintf(stderr, "created signed-data message\n"); - } - if (ekpcert) { - CERT_DestroyCertificate(ekpcert); - } - if (cert) { - CERT_DestroyCertificate(cert); - } - return cmsg; -loser: - if (ekpcert) { - CERT_DestroyCertificate(ekpcert); - } - if (cert) { - CERT_DestroyCertificate(cert); - } - NSS_CMSMessage_Destroy(cmsg); - return NULL; -} - -static NSSCMSMessage * -enveloped_data(struct envelopeOptionsStr *envelopeOptions) -{ - NSSCMSMessage *cmsg = NULL; - NSSCMSContentInfo *cinfo; - NSSCMSEnvelopedData *envd; - NSSCMSRecipientInfo *recipientinfo; - CERTCertificate **recipientcerts = NULL; - CERTCertDBHandle *dbhandle; - PLArenaPool *tmppoolp = NULL; - SECOidTag bulkalgtag; - int keysize, i = 0; - int cnt; - dbhandle = envelopeOptions->options->certHandle; - /* count the recipients */ - if ((cnt = nss_CMSArray_Count((void **)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]); - i=0; - goto loser; - } - } - recipientcerts[i] = NULL; - i=0; - /* 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; - } - CERT_DestroyCertificate(recipientcerts[i]); - } - if (tmppoolp) - PORT_FreeArena(tmppoolp, PR_FALSE); - return cmsg; -loser: - if (recipientcerts) { - for (; recipientcerts[i] != NULL; i++) { - CERT_DestroyCertificate(recipientcerts[i]); - } - } - 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; - 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 = (unsigned char *)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 - */ - encryptOptions->bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo); - encryptOptions->keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo); - encryptOptions->bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo); - rv = SECSuccess; - break; - } - } - if (i == nlevels) { - fprintf(stderr, "%s: could not retrieve enveloped data.", progName); - } - 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, (char *)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 = NULL; - CERTCertDBHandle *dbhandle; - PLArenaPool *tmppoolp = NULL; - int i = 0, cnt; - dbhandle = certsonlyOptions->options->certHandle; - if ((cnt = nss_CMSArray_Count((void**)certsonlyOptions->recipients)) == 0) { - fprintf(stderr, - "ERROR: please indicate the nickname of a certificate to sign with.\n"); - goto loser; - } - if (!(tmppoolp = PORT_NewArena(1024))) { - fprintf(stderr, "ERROR: out of memory.\n"); - goto loser; - } - if (!(certs = PORT_ArenaZNewArray(tmppoolp, CERTCertificate *, cnt + 1))) { - 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]); - i=0; - goto loser; - } - } - certs[i] = NULL; - i=0; - /* - * 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; - } - CERT_DestroyCertificate(certs[0]); - 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; - } - CERT_DestroyCertificate(certs[i]); - } - 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 (certs) { - for (; i<cnt; i++) { - CERT_DestroyCertificate(certs[i]); - } - } - if (cmsg) - NSS_CMSMessage_Destroy(cmsg); - if (tmppoolp) - PORT_FreeArena(tmppoolp, PR_FALSE); - return NULL; -} - -static char * -pl_fgets(char * buf, int size, PRFileDesc * fd) -{ - char * bp = buf; - int nb = 0;; - - while (size > 1) { - nb = PR_Read(fd, bp, 1); - if (nb < 0) { - /* deal with error */ - return NULL; - } else if (nb == 0) { - /* deal with EOF */ - return NULL; - } else if (*bp == '\n') { - /* deal with EOL */ - ++bp; /* keep EOL character */ - break; - } else { - /* ordinary character */ - ++bp; - --size; - } - } - *bp = '\0'; - return buf; -} - -typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode; - -static int -doBatchDecode(FILE *outFile, PRFileDesc *batchFile, - const struct decodeOptionsStr *decodeOptions) -{ - char * str; - int exitStatus = 0; - char batchLine[512]; - - while (NULL != (str = pl_fgets(batchLine, sizeof batchLine, batchFile))) { - NSSCMSMessage *cmsg = NULL; - PRFileDesc * inFile; - int len = strlen(str); - SECStatus rv; - SECItem input = {0, 0, 0}; - char cc; - - while (len > 0 && - ((cc = str[len - 1]) == '\n' || cc == '\r')) { - str[--len] = '\0'; - } - if (!len) /* skip empty line */ - continue; - if (str[0] == '#') - continue; /* skip comment line */ - fprintf(outFile, "========== %s ==========\n", str); - inFile = PR_Open(str, PR_RDONLY, 00660); - if (inFile == NULL) { - fprintf(outFile, "%s: unable to open \"%s\" for reading\n", - progName, str); - exitStatus = 1; - continue; - } - rv = SECU_FileToItem(&input, inFile); - PR_Close(inFile); - if (rv != SECSuccess) { - SECU_PrintError(progName, "unable to read infile"); - exitStatus = 1; - continue; - } - cmsg = decode(outFile, &input, decodeOptions); - SECITEM_FreeItem(&input, PR_FALSE); - if (cmsg) - NSS_CMSMessage_Destroy(cmsg); - else { - SECU_PrintError(progName, "problem decoding"); - exitStatus = 1; - } - } - return exitStatus; -} - -int -main(int argc, char **argv) -{ - FILE *outFile; - NSSCMSMessage *cmsg = NULL; - PRFileDesc *inFile; - PLOptState *optstate; - PLOptStatus status; - Mode mode = UNKNOWN; - 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 envmsg = { 0, 0, 0 }; - SECStatus rv; - PRFileDesc *contentFile = NULL; - PRBool batch = PR_FALSE; - -#ifdef NISCC_TEST - const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST"); - PORT_Assert(ev); - ev = PR_GetEnv("NSS_STRICT_SHUTDOWN"); - PORT_Assert(ev); -#endif - - progName = strrchr(argv[0], '/'); - if (!progName) - progName = strrchr(argv[0], '\\'); - progName = progName ? progName+1 : argv[0]; - - inFile = PR_STDIN; - outFile = stdout; - envFileName = NULL; - mode = UNKNOWN; - decodeOptions.content.data = NULL; - decodeOptions.content.len = 0; - decodeOptions.suppressContent = PR_FALSE; - decodeOptions.headerLevel = -1; - decodeOptions.keepCerts = PR_FALSE; - options.certUsage = certUsageEmailSigner; - options.password = NULL; - options.pwfile = NULL; - signOptions.nickname = NULL; - signOptions.detached = PR_FALSE; - signOptions.signingTime = PR_FALSE; - signOptions.smimeProfile = PR_FALSE; - signOptions.encryptionKeyPreferenceNick = NULL; - signOptions.hashAlgTag = SEC_OID_SHA1; - 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, - "CDEGH:N:OPSTY:bc:d:e:f:h:i:kno:p:r:s:u:v"); - while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { - switch (optstate->option) { - case 'C': - mode = ENCRYPT; - break; - case 'D': - mode = DECODE; - break; - case 'E': - mode = ENVELOPE; - 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 'H': - if (mode != SIGN) { - fprintf(stderr, - "%s: option -H only supported with option -S.\n", - progName); - Usage(progName); - exit(1); - } - decodeOptions.suppressContent = PR_TRUE; - if (!strcmp(optstate->value, "MD2")) - signOptions.hashAlgTag = SEC_OID_MD2; - else if (!strcmp(optstate->value, "MD4")) - signOptions.hashAlgTag = SEC_OID_MD4; - else if (!strcmp(optstate->value, "MD5")) - signOptions.hashAlgTag = SEC_OID_MD5; - else if (!strcmp(optstate->value, "SHA1")) - signOptions.hashAlgTag = SEC_OID_SHA1; - else if (!strcmp(optstate->value, "SHA256")) - signOptions.hashAlgTag = SEC_OID_SHA256; - else if (!strcmp(optstate->value, "SHA384")) - signOptions.hashAlgTag = SEC_OID_SHA384; - else if (!strcmp(optstate->value, "SHA512")) - signOptions.hashAlgTag = SEC_OID_SHA512; - else { - fprintf(stderr, - "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n", - progName); - exit(1); - } - 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 'O': - mode = CERTSONLY; - 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 'S': - mode = SIGN; - 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 '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 'b': - if (mode != DECODE) { - fprintf(stderr, - "%s: option -b only supported with option -D.\n", - progName); - Usage(progName); - exit(1); - } - batch = PR_TRUE; - break; - - case 'c': - if (mode != DECODE) { - fprintf(stderr, - "%s: option -c only supported with option -D.\n", - progName); - Usage(progName); - exit(1); - } - contentFile = PR_Open(optstate->value, PR_RDONLY, 006600); - if (contentFile == NULL) { - fprintf(stderr, "%s: unable to open \"%s\" for reading.\n", - progName, optstate->value); - exit(1); - } - - rv = SECU_FileToItem(&decodeOptions.content, contentFile); - PR_Close(contentFile); - if (rv != SECSuccess) { - SECU_PrintError(progName, "problem reading content file"); - exit(1); - } - if (!decodeOptions.content.data) { - /* file was zero length */ - decodeOptions.content.data = (unsigned char *)PORT_Strdup(""); - decodeOptions.content.len = 0; - } - - break; - case 'd': - SECU_ConfigDirectory(optstate->value); - break; - case 'e': - envFileName = strdup(optstate->value); - encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660); - 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 'i': - if (!optstate->value) { - fprintf(stderr, "-i option requires filename argument\n"); - exit(1); - } - inFile = PR_Open(optstate->value, PR_RDONLY, 00660); - if (inFile == NULL) { - fprintf(stderr, "%s: unable to open \"%s\" for reading\n", - progName, optstate->value); - exit(1); - } - break; - - case 'k': - if (mode != DECODE) { - fprintf(stderr, - "%s: option -k only supported with option -D.\n", - progName); - Usage(progName); - exit(1); - } - decodeOptions.keepCerts = PR_TRUE; - 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 'o': - outFile = fopen(optstate->value, "wb"); - if (outFile == NULL) { - fprintf(stderr, "%s: unable to open \"%s\" for writing\n", - progName, optstate->value); - 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 'f': - if (!optstate->value) { - fprintf(stderr, "%s: option -f must have a value.\n", progName); - Usage(progName); - exit(1); - } - - options.pwfile = strdup(optstate->value); - break; - - case 'r': - if (!optstate->value) { - fprintf(stderr, "%s: option -r must have a value.\n", progName); - Usage(progName); - exit(1); - } - envelopeOptions.recipients = ptrarray; - str = (char *)optstate->value; - do { - tok = strchr(str, ','); - if (tok) *tok = '\0'; - 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 'u': { - int usageType; - - usageType = atoi (strdup(optstate->value)); - if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) - return -1; - options.certUsage = (SECCertUsage)usageType; - break; - } - case 'v': - cms_verbose = 1; - break; - - } - } - if (status == PL_OPT_BAD) - Usage(progName); - PL_DestroyOptState(optstate); - - if (mode == UNKNOWN) - Usage(progName); - - if (mode != CERTSONLY && !batch) { - rv = SECU_FileToItem(&input, inFile); - if (rv != SECSuccess) { - SECU_PrintError(progName, "unable to read infile"); - exit(1); - } - if (inFile != PR_STDIN) { - PR_Close(inFile); - } - } - if (cms_verbose) { - fprintf(stderr, "received commands\n"); - } - - /* Call the NSS 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); - } - if (cms_verbose) { - fprintf(stderr, "NSS has been initialized.\n"); - } - options.certHandle = CERT_GetDefaultCertDB(); - if (!options.certHandle) { - SECU_PrintError(progName, "No default cert DB"); - exit(1); - } - if (cms_verbose) { - fprintf(stderr, "Got default certdb\n"); - } - if (options.password) - { - pwdata.source = PW_PLAINTEXT; - pwdata.data = options.password; - } - if (options.pwfile) - { - pwdata.source = PW_FROMFILE; - pwdata.data = options.pwfile; - } - pwcb = SECU_GetModulePassword; - pwcb_arg = (void *)&pwdata; - - PK11_SetPasswordFunc(&SECU_GetModulePassword); - - -#if defined(_WIN32) - 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 \r\n'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: /* -D */ - 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, &envmsg, &decodeOptions); - if (!encryptOptions.envmsg) { - SECU_PrintError(progName, "problem decoding env msg"); - exitstatus = 1; - break; - } - rv = get_enc_params(&encryptOptions); - decodeOptions.dkcb = dkcb; - decodeOptions.bulkkey = encryptOptions.bulkkey; - } - if (!batch) { - cmsg = decode(outFile, &input, &decodeOptions); - if (!cmsg) { - SECU_PrintError(progName, "problem decoding"); - exitstatus = 1; - } - } else { - exitstatus = doBatchDecode(outFile, inFile, &decodeOptions); - if (inFile != PR_STDIN) { - PR_Close(inFile); - } - } - break; - case SIGN: /* -S */ - signOptions.options = &options; - cmsg = signed_data(&signOptions); - if (!cmsg) { - SECU_PrintError(progName, "problem signing"); - exitstatus = 1; - } - break; - case ENCRYPT: /* -C */ - 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; - /* decode an enveloped-data message to get the bulkkey (create - * a new one if neccessary) - */ - 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, &envmsg, &decodeOptions); - if (encryptOptions.envmsg == NULL) { - SECU_PrintError(progName, "problem decrypting env msg"); - exitstatus = 1; - break; - } - } - rv = get_enc_params(&encryptOptions); - /* create the encrypted-data message */ - cmsg = encrypted_data(&encryptOptions); - if (!cmsg) { - SECU_PrintError(progName, "problem encrypting"); - exitstatus = 1; - } - if (encryptOptions.bulkkey) { - PK11_FreeSymKey(encryptOptions.bulkkey); - encryptOptions.bulkkey = NULL; - } - break; - case ENVELOPE: /* -E */ - envelopeOptions.options = &options; - cmsg = enveloped_data(&envelopeOptions); - if (!cmsg) { - SECU_PrintError(progName, "problem enveloping"); - exitstatus = 1; - } - break; - case CERTSONLY: /* -O */ - 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) - && (!exitstatus) ) { - PLArenaPool *arena = PORT_NewArena(1024); - NSSCMSEncoderContext *ecx; - SECItem output = { 0, 0, 0 }; - - if (!arena) { - fprintf(stderr, "%s: out of memory.\n", progName); - exit(1); - } - - if (cms_verbose) { - fprintf(stderr, "cmsg [%p]\n", cmsg); - fprintf(stderr, "arena [%p]\n", arena); - if (pwcb_arg && (PW_PLAINTEXT == ((secuPWData*)pwcb_arg)->source)) - fprintf(stderr, "password [%s]\n", - ((secuPWData*)pwcb_arg)->data); - else - fprintf(stderr, "password [NULL]\n"); - } - 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 (cms_verbose) { - fprintf(stderr, "input len [%d]\n", input.len); - { unsigned int j; - for(j=0;j<input.len;j++) - fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' '); - } - } - if (input.len > 0) { /* skip if certs-only (or other zero content) */ - rv = NSS_CMSEncoder_Update(ecx, (char *)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) { - SECU_PrintError(progName, "failed to encode data"); - exit(1); - } - - if (cms_verbose) { - fprintf(stderr, "encoding passed\n"); - } - fwrite(output.data, output.len, 1, outFile); - if (cms_verbose) { - fprintf(stderr, "wrote to file\n"); - } - PORT_FreeArena(arena, PR_FALSE); - } - if (cmsg) - NSS_CMSMessage_Destroy(cmsg); - if (outFile != stdout) - fclose(outFile); - - SECITEM_FreeItem(&decodeOptions.content, PR_FALSE); - SECITEM_FreeItem(&envmsg, PR_FALSE); - SECITEM_FreeItem(&input, PR_FALSE); - if (NSS_Shutdown() != SECSuccess) { - SECU_PrintError(progName, "NSS_Shutdown failed"); - exitstatus = 1; - } - PR_Cleanup(); - return exitstatus; -} diff --git a/security/nss/cmd/smimetools/manifest.mn b/security/nss/cmd/smimetools/manifest.mn deleted file mode 100644 index ac2052ac4..000000000 --- a/security/nss/cmd/smimetools/manifest.mn +++ /dev/null @@ -1,49 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# 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 the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -CORE_DEPTH = ../../.. - -MODULE = nss - -CSRCS = cmsutil.c - -MYLIB = $(DIST)/lib/libsmime.a - -REQUIRES = seccmd dbm - -PROGRAM = cmsutil -SCRIPTS = smime diff --git a/security/nss/cmd/smimetools/rules.mk b/security/nss/cmd/smimetools/rules.mk deleted file mode 100644 index 1743a5e42..000000000 --- a/security/nss/cmd/smimetools/rules.mk +++ /dev/null @@ -1,40 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# 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 the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** -# $Id$ - -install:: - $(INSTALL) -m 755 $(SCRIPTS) $(SOURCE_BIN_DIR) diff --git a/security/nss/cmd/smimetools/smime b/security/nss/cmd/smimetools/smime deleted file mode 100755 index 0ac312e05..000000000 --- a/security/nss/cmd/smimetools/smime +++ /dev/null @@ -1,581 +0,0 @@ -#!/usr/local/bin/perl - -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# 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 the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -# -# smime.pl - frontend for S/MIME message generation and parsing -# -# $Id$ -# - -use Getopt::Std; - -@boundarychars = ( "0" .. "9", "A" .. "F" ); - -# path to cmsutil -$cmsutilpath = "cmsutil"; - -# -# Thanks to Gisle Aas <gisle@aas.no> for the base64 functions -# originally taken from MIME-Base64-2.11 at www.cpan.org -# -sub encode_base64($) -{ - my $res = ""; - pos($_[0]) = 0; # ensure start at the beginning - while ($_[0] =~ /(.{1,45})/gs) { - $res .= substr(pack('u', $1), 1); # get rid of length byte after packing - chop($res); - } - $res =~ tr|` -_|AA-Za-z0-9+/|; - # fix padding at the end - my $padding = (3 - length($_[0]) % 3) % 3; - $res =~ s/.{$padding}$/'=' x $padding/e if $padding; - # break encoded string into lines of no more than 76 characters each - $res =~ s/(.{1,76})/$1\n/g; - $res; -} - -sub decode_base64($) -{ - local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123] - - my $str = shift; - my $res = ""; - - $str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars - if (length($str) % 4) { - require Carp; - Carp::carp("Length of base64 data not a multiple of 4") - } - $str =~ s/=+$//; # remove padding - $str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format - while ($str =~ /(.{1,60})/gs) { - my $len = chr(32 + length($1)*3/4); # compute length byte - $res .= unpack("u", $len . $1 ); # uudecode - } - $res; -} - -# -# parse headers into a hash -# -# %headers = parseheaders($headertext); -# -sub parseheaders($) -{ - my ($headerdata) = @_; - my $hdr; - my %hdrhash; - my $hdrname; - my $hdrvalue; - my @hdrvalues; - my $subhdrname; - my $subhdrvalue; - - # the expression in split() correctly handles continuation lines - foreach $hdr (split(/\n(?=\S)/, $headerdata)) { - $hdr =~ s/\r*\n\s+/ /g; # collapse continuation lines - ($hdrname, $hdrvalue) = $hdr =~ m/^(\S+):\s+(.*)$/; - - # ignore non-headers (or should we die horribly?) - next unless (defined($hdrname)); - $hdrname =~ tr/A-Z/a-z/; # lowercase the header name - @hdrvalues = split(/\s*;\s*/, $hdrvalue); # split header values (XXXX quoting) - - # there is guaranteed to be at least one value - $hdrvalue = shift @hdrvalues; - if ($hdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there - $hdrvalue = $1; - } - - $hdrhash{$hdrname}{MAIN} = $hdrvalue; - # print "XXX $hdrname = $hdrvalue\n"; - - # deal with additional name-value pairs - foreach $hdrvalue (@hdrvalues) { - ($subhdrname, $subhdrvalue) = $hdrvalue =~ m/^(\S+)\s*=\s*(.*)$/; - # ignore non-name-value pairs (or should we die?) - next unless (defined($subhdrname)); - $subhdrname =~ tr/A-Z/a-z/; - if ($subhdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there - $subhdrvalue = $1; - } - $hdrhash{$hdrname}{$subhdrname} = $subhdrvalue; - } - - } - return %hdrhash; -} - -# -# encryptentity($entity, $options) - encrypt an S/MIME entity, -# creating a new application/pkcs7-smime entity -# -# entity - string containing entire S/MIME entity to encrypt -# options - options for cmsutil -# -# this will generate and return a new application/pkcs7-smime entity containing -# the enveloped input entity. -# -sub encryptentity($$) -{ - my ($entity, $cmsutiloptions) = @_; - my $out = ""; - my $boundary; - - $tmpencfile = "/tmp/encryptentity.$$"; - - # - # generate a random boundary string - # - $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]); - - # - # tell cmsutil to generate a enveloped CMS message using our data - # - open(CMS, "|$cmsutilpath -E $cmsutiloptions -o $tmpencfile") or die "ERROR: cannot pipe to cmsutil"; - print CMS $entity; - unless (close(CMS)) { - print STDERR "ERROR: encryption failed.\n"; - unlink($tmpsigfile); - exit 1; - } - - $out = "Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m\n"; - $out .= "Content-Transfer-Encoding: base64\n"; - $out .= "Content-Disposition: attachment; filename=smime.p7m\n"; - $out .= "\n"; # end of entity header - - open (ENC, $tmpencfile) or die "ERROR: cannot find newly generated encrypted content"; - local($/) = undef; # slurp whole file - $out .= encode_base64(<ENC>), "\n"; # entity body is base64-encoded CMS message - close(ENC); - - unlink($tmpencfile); - - $out; -} - -# -# signentity($entity, $options) - sign an S/MIME entity -# -# entity - string containing entire S/MIME entity to sign -# options - options for cmsutil -# -# this will generate and return a new multipart/signed entity consisting -# of the canonicalized original content, plus a signature block. -# -sub signentity($$) -{ - my ($entity, $cmsutiloptions) = @_; - my $out = ""; - my $boundary; - - $tmpsigfile = "/tmp/signentity.$$"; - - # - # generate a random boundary string - # - $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]); - - # - # tell cmsutil to generate a signed CMS message using the canonicalized data - # The signedData has detached content (-T) and includes a signing time attribute (-G) - # - # if we do not provide a password on the command line, here's where we would be asked for it - # - open(CMS, "|$cmsutilpath -S -T -G $cmsutiloptions -o $tmpsigfile") or die "ERROR: cannot pipe to cmsutil"; - print CMS $entity; - unless (close(CMS)) { - print STDERR "ERROR: signature generation failed.\n"; - unlink($tmpsigfile); - exit 1; - } - - open (SIG, $tmpsigfile) or die "ERROR: cannot find newly generated signature"; - - # - # construct a new multipart/signed MIME entity consisting of the original content and - # the signature - # - # (we assume that cmsutil generates a SHA1 digest) - $out .= "Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1; boundary=\"${boundary}\"\n"; - $out .= "\n"; # end of entity header - $out .= "This is a cryptographically signed message in MIME format.\n"; # explanatory comment - $out .= "\n--${boundary}\n"; - $out .= $entity; - $out .= "\n--${boundary}\n"; - $out .= "Content-Type: application/pkcs7-signature; name=smime.p7s\n"; - $out .= "Content-Transfer-Encoding: base64\n"; - $out .= "Content-Disposition: attachment; filename=smime.p7s\n"; - $out .= "Content-Description: S/MIME Cryptographic Signature\n"; - $out .= "\n"; # end of signature subentity header - - local($/) = undef; # slurp whole file - $out .= encode_base64(<SIG>); # append base64-encoded signature - $out .= "\n--${boundary}--\n"; - - close(SIG); - unlink($tmpsigfile); - - $out; -} - -sub usage { - print STDERR "usage: smime [options]\n"; - print STDERR " options:\n"; - print STDERR " -S nick generate signed message, use certificate named \"nick\"\n"; - print STDERR " -p passwd use \"passwd\" as security module password\n"; - print STDERR " -E rec1[,rec2...] generate encrypted message for recipients\n"; - print STDERR " -D decode a S/MIME message\n"; - print STDERR " -p passwd use \"passwd\" as security module password\n"; - print STDERR " (required for decrypting only)\n"; - print STDERR " -C pathname set pathname of \"cmsutil\"\n"; - print STDERR " -d directory set directory containing certificate db\n"; - print STDERR " (default: ~/.netscape)\n"; - print STDERR "\nWith -S or -E, smime will take a regular RFC822 message or MIME entity\n"; - print STDERR "on stdin and generate a signed or encrypted S/MIME message with the same\n"; - print STDERR "headers and content from it. The output can be used as input to a MTA.\n"; - print STDERR "-D causes smime to strip off all S/MIME layers if possible and output\n"; - print STDERR "the \"inner\" message.\n"; -} - -# -# start of main procedures -# - -# -# process command line options -# -unless (getopts('S:E:p:d:C:D')) { - usage(); - exit 1; -} - -unless (defined($opt_S) or defined($opt_E) or defined($opt_D)) { - print STDERR "ERROR: -S and/or -E, or -D must be specified.\n"; - usage(); - exit 1; -} - -$signopts = ""; -$encryptopts = ""; -$decodeopts = ""; - -# pass -d option along -if (defined($opt_d)) { - $signopts .= "-d \"$opt_d\" "; - $encryptopts .= "-d \"$opt_d\" "; - $decodeopts .= "-d \"$opt_d\" "; -} - -if (defined($opt_S)) { - $signopts .= "-N \"$opt_S\" "; -} - -if (defined($opt_p)) { - $signopts .= "-p \"$opt_p\" "; - $decodeopts .= "-p \"$opt_p\" "; -} - -if (defined($opt_E)) { - @recipients = split(",", $opt_E); - $encryptopts .= "-r "; - $encryptopts .= join (" -r ", @recipients); -} - -if (defined($opt_C)) { - $cmsutilpath = $opt_C; -} - -# -# split headers into mime entity headers and RFC822 headers -# The RFC822 headers are preserved and stay on the outer layer of the message -# -$rfc822headers = ""; -$mimeheaders = ""; -$mimebody = ""; -$skippedheaders = ""; -while (<STDIN>) { - last if (/^$/); - if (/^content-\S+: /i) { - $lastref = \$mimeheaders; - } elsif (/^mime-version: /i) { - $lastref = \$skippedheaders; # skip it - } elsif (/^\s/) { - ; - } else { - $lastref = \$rfc822headers; - } - $$lastref .= $_; -} - -# -# if there are no MIME entity headers, generate some default ones -# -if ($mimeheaders eq "") { - $mimeheaders .= "Content-Type: text/plain; charset=us-ascii\n"; - $mimeheaders .= "Content-Transfer-Encoding: 7bit\n"; -} - -# -# slurp in the entity body -# -$saveRS = $/; -$/ = undef; -$mimebody = <STDIN>; -$/ = $saveRS; -chomp($mimebody); - -if (defined $opt_D) { - # - # decode - # - # possible options would be: - # - strip off only one layer - # - strip off outer signature (if present) - # - just print information about the structure of the message - # - strip n layers, then dump DER of CMS message - - $layercounter = 1; - - while (1) { - %hdrhash = parseheaders($mimeheaders); - unless (exists($hdrhash{"content-type"}{MAIN})) { - print STDERR "ERROR: no content type header found in MIME entity\n"; - last; # no content-type - we're done - } - - $contenttype = $hdrhash{"content-type"}{MAIN}; - if ($contenttype eq "application/pkcs7-mime") { - # - # opaque-signed or enveloped message - # - unless (exists($hdrhash{"content-type"}{"smime-type"})) { - print STDERR "ERROR: no smime-type attribute in application/pkcs7-smime entity.\n"; - last; - } - $smimetype = $hdrhash{"content-type"}{"smime-type"}; - if ($smimetype eq "signed-data" or $smimetype eq "enveloped-data") { - # it's verification or decryption time! - - # can handle only base64 encoding for now - # all other encodings are treated as binary (8bit) - if ($hdrhash{"content-transfer-encoding"}{MAIN} eq "base64") { - $mimebody = decode_base64($mimebody); - } - - # if we need to dump the DER, we would do it right here - - # now write the DER - $tmpderfile = "/tmp/der.$$"; - open(TMP, ">$tmpderfile") or die "ERROR: cannot write signature data to temporary file"; - print TMP $mimebody; - unless (close(TMP)) { - print STDERR "ERROR: writing signature data to temporary file.\n"; - unlink($tmpderfile); - exit 1; - } - - $mimeheaders = ""; - open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -i $tmpderfile |") or die "ERROR: cannot open pipe to cmsutil"; - $layercounter++; - while (<TMP>) { - last if (/^\r?$/); # empty lines mark end of header - if (/^SMIME: /) { # add all SMIME info to the rfc822 hdrs - $lastref = \$rfc822headers; - } elsif (/^\s/) { - ; # continuation lines go to the last dest - } else { - $lastref = \$mimeheaders; # all other headers are mime headers - } - $$lastref .= $_; - } - # slurp in rest of the data to $mimebody - $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS; - close(TMP); - - unlink($tmpderfile); - - } else { - print STDERR "ERROR: unknown smime-type \"$smimetype\" in application/pkcs7-smime entity.\n"; - last; - } - } elsif ($contenttype eq "multipart/signed") { - # - # clear signed message - # - unless (exists($hdrhash{"content-type"}{"protocol"})) { - print STDERR "ERROR: content type has no protocol attribute in multipart/signed entity.\n"; - last; - } - if ($hdrhash{"content-type"}{"protocol"} ne "application/pkcs7-signature") { - # we cannot handle this guy - print STDERR "ERROR: unknown protocol \"", $hdrhash{"content-type"}{"protocol"}, - "\" in multipart/signed entity.\n"; - last; - } - unless (exists($hdrhash{"content-type"}{"boundary"})) { - print STDERR "ERROR: no boundary attribute in multipart/signed entity.\n"; - last; - } - $boundary = $hdrhash{"content-type"}{"boundary"}; - - # split $mimebody along \n--$boundary\n - gets you four parts - # first (0), any comments the sending agent might have put in - # second (1), the message itself - # third (2), the signature as a mime entity - # fourth (3), trailing data (there shouldn't be any) - - @multiparts = split(/\r?\n--$boundary(?:--)?\r?\n/, $mimebody); - - # - # parse the signature headers - ($submimeheaders, $submimebody) = split(/^$/m, $multiparts[2]); - %sighdrhash = parseheaders($submimeheaders); - unless (exists($sighdrhash{"content-type"}{MAIN})) { - print STDERR "ERROR: signature entity has no content type.\n"; - last; - } - if ($sighdrhash{"content-type"}{MAIN} ne "application/pkcs7-signature") { - # we cannot handle this guy - print STDERR "ERROR: unknown content type \"", $sighdrhash{"content-type"}{MAIN}, - "\" in signature entity.\n"; - last; - } - if ($sighdrhash{"content-transfer-encoding"}{MAIN} eq "base64") { - $submimebody = decode_base64($submimebody); - } - - # we would dump the DER at this point - - $tmpsigfile = "/tmp/sig.$$"; - open(TMP, ">$tmpsigfile") or die "ERROR: cannot write signature data to temporary file"; - print TMP $submimebody; - unless (close(TMP)) { - print STDERR "ERROR: writing signature data to temporary file.\n"; - unlink($tmpsigfile); - exit 1; - } - - $tmpmsgfile = "/tmp/msg.$$"; - open(TMP, ">$tmpmsgfile") or die "ERROR: cannot write message data to temporary file"; - print TMP $multiparts[1]; - unless (close(TMP)) { - print STDERR "ERROR: writing message data to temporary file.\n"; - unlink($tmpsigfile); - unlink($tmpmsgfile); - exit 1; - } - - $mimeheaders = ""; - open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -c $tmpmsgfile -i $tmpsigfile |") or die "ERROR: cannot open pipe to cmsutil"; - $layercounter++; - while (<TMP>) { - last if (/^\r?$/); - if (/^SMIME: /) { - $lastref = \$rfc822headers; - } elsif (/^\s/) { - ; - } else { - $lastref = \$mimeheaders; - } - $$lastref .= $_; - } - $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS; - close(TMP); - unlink($tmpsigfile); - unlink($tmpmsgfile); - - } else { - - # not a content type we know - we're done - last; - - } - } - - # so now we have the S/MIME parsing information in rfc822headers - # and the first mime entity we could not handle in mimeheaders and mimebody. - # dump 'em out and we're done. - print $rfc822headers; - print $mimeheaders . "\n" . $mimebody; - -} else { - - # - # encode (which is much easier than decode) - # - - $mimeentity = $mimeheaders . "\n" . $mimebody; - - # - # canonicalize inner entity (rudimentary yet) - # convert single LFs to CRLF - # if no Content-Transfer-Encoding header present: - # if 8 bit chars present, use Content-Transfer-Encoding: quoted-printable - # otherwise, use Content-Transfer-Encoding: 7bit - # - $mimeentity =~ s/\r*\n/\r\n/mg; - - # - # now do the wrapping - # we sign first, then encrypt because that's what Communicator needs - # - if (defined($opt_S)) { - $mimeentity = signentity($mimeentity, $signopts); - } - - if (defined($opt_E)) { - $mimeentity = encryptentity($mimeentity, $encryptopts); - } - - # - # XXX sign again to do triple wrapping (RFC2634) - # - - # - # now write out the RFC822 headers - # followed by the final $mimeentity - # - print $rfc822headers; - print "MIME-Version: 1.0 (NSS SMIME - http://www.mozilla.org/projects/security)\n"; # set up the flag - print $mimeentity; -} - -exit 0; |