Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/cmd/smimetools/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 58 kB image not shown  

Quelle  cmsutil.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
 * cmsutil -- A command to work with CMS data
 */


#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"
#include "sechash.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(void)
{
    fprintf(stderr,
            "Usage: %s [-C|-D|-E|-O|-S] [] [-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:SHA256)\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"" ");
    fprintf(stderr, "%-25s 12 - certUsageIPsec\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 = NULL;
                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.
                    */

                    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;
                    }
                    /* if the signatures validate and we asked to keep
                     * the certs, save the profiles */

                    if (decodeOptions->keepCerts) {
                        rv = NSS_SMIMESignerInfo_SaveSMIMEProfile(si);
                        if (rv != SECSuccess) {
                            SECU_PrintError(progName, "SMIME profile import failed");
                            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 = NULL;
    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");
    }
    signerinfo->cmsg->pwfn_arg = pwcb_arg;
    /* 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;
    }
    signerinfo = NULL; /* sigd has adopted signerinfo */
    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);
    }
    if (signerinfo) {
        NSS_CMSSignerInfo_Destroy(signerinfo);
    }
    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;
}

/* legacy SHA2 table...
 * cmsutil took hash values of SHA256, SHA244, etc., the the
 * oid table has values of SHA-256, SHA-224. Use the follow
 * table to handle the old values. NOTE: no need to add new
 * hashes to this table, just use the actual oid table
 * values */

typedef struct LegacyHashNameStr {
    char *name;
    SECOidTag tag;
} LegacyHashName;

LegacyHashName legacyHashNamesTable[] = {
    { "SHA1", SEC_OID_SHA1 },
    { "SHA224", SEC_OID_SHA224 },
    { "SHA256", SEC_OID_SHA256 },
    { "SHA384", SEC_OID_SHA384 },
    { "SHA512", SEC_OID_SHA512 },
};
size_t legacyHashNamesTableSize = PR_ARRAY_SIZE(legacyHashNamesTable);

SECOidTag
CMSU_FindTagFromString(const char *cipherString)
{
    SECOidTag tag;
    SECOidData *oid;
    size_t slen;

    /* future enhancement: accept dotted oid spec? */

    for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
        /* only interested in oids that we actually understand */
        if (oid->mechanism == CKM_INVALID_MECHANISM) {
            continue;
        }
        if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
            continue;
        }
        return tag;
    }
    slen = PORT_Strlen(cipherString);
    if ((slen > 3) && (PORT_Strncasecmp(cipherString, "SHA", 3) == 0) &&
        (cipherString[3] != '-')) {
        int i;
        for (i = 0; i < legacyHashNamesTableSize; i++) {
            if (PORT_Strcasecmp(legacyHashNamesTable[i].name, cipherString) == 0) {
                return legacyHashNamesTable[i].tag;
            }
        }
        /* not on any table, must be invalid */
    }
    return SEC_OID_UNKNOWN;
}

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_GetEnvSecure("NSS_DISABLE_ARENA_FREE_LIST");
    PORT_Assert(ev);
    ev = PR_GetEnvSecure("NSS_STRICT_SHUTDOWN");
    PORT_Assert(ev);
#endif

    SECOID_Init();

    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_SHA256;
    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();
                    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();
                    exit(1);
                }
                decodeOptions.suppressContent = PR_TRUE;
                /* lookup hash value from our oid table and make sure it's a hash
                 * using HASH_ functions */

                signOptions.hashAlgTag = CMSU_FindTagFromString(optstate->value);
                if (HASH_GetHashTypeByOidTag(signOptions.hashAlgTag) == HASH_AlgNULL) {
                    char *comma = "";
                    int i;
                    /* it wasn't, use the HASH_ functions to find the valid values
                     * and print it as an error */

                    fprintf(stderr,
                            "%s: -H requires one of ", progName);
                    for (i = HASH_AlgNULL + 1; PR_TRUE; i++) {
                        SECOidTag hashTag = HASH_GetHashOidTagByHashType(i);
                        if (hashTag == SEC_OID_UNKNOWN) {
                            fprintf(stderr, "\n");
                            exit(1);
                        }
                        fprintf(stderr, "%s%s", comma, SECOID_FindOIDTagDescription(hashTag));
                        comma = ",";
                    }
                    /* NOT REACHED */
                }
                break;
            case 'N':
                if (mode != SIGN) {
                    fprintf(stderr,
                            "%s: option -N only supported with option -S.\n",
                            progName);
                    Usage();
                    exit(1);
                }
                signOptions.nickname = PORT_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();
                    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();
                    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();
                    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();
                    exit(1);
                }
                batch = PR_TRUE;
                break;

            case 'c':
                if (mode != DECODE) {
                    fprintf(stderr,
                            "%s: option -c only supported with option -D.\n",
                            progName);
                    Usage();
                    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 = PORT_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();
                    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();
                    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();
                    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();
                    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();
                    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();
                    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();
    PL_DestroyOptState(optstate);

    if (mode == UNKNOWN)
        Usage();

    if (mode != CERTSONLY && !batch) {
        rv = SECU_FileToItem(&input, inFile);
        if (rv != SECSuccess) {
            SECU_PrintError(progName, "unable to read infile");
            exit(1);
        }
    }
    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);
            }
            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();
            exitstatus = 1;
    }

    if (signOptions.nickname) {
        PORT_Free(signOptions.nickname);
    }

    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);

    if (inFile != PR_STDIN) {
        PR_Close(inFile);
    }
    if (envFileName) {
        PORT_Free(envFileName);
    }
    if (encryptOptions.envFile) {
        PR_Close(encryptOptions.envFile);
    }

    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;
}

Messung V0.5
C=89 H=87 G=87

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.