cmsutil.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,277 行 · 第 1/3 页

C
1,277
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * cmsutil -- A command to work with CMS data * * $Id: cmsutil.c,v 1.15 2000/10/11 07:21:38 wtc%netscape.com Exp $ */#include "nspr.h"#include "secutil.h"#include "plgetopt.h"#include "secpkcs7.h"#include "cert.h"#include "certdb.h"#include "cdbhdl.h"#include "secoid.h"#include "cms.h"#include "nss.h"#include "smime.h"#if defined(XP_UNIX)#include <unistd.h>#endif#include <stdio.h>#include <string.h>extern void SEC_Init(void);		/* XXX */char *progName = NULL;static SECStatusDigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input,           SECAlgorithmID **algids){    NSSCMSDigestContext *digcx;    digcx = NSS_CMSDigestContext_StartMultiple(algids);    if (digcx == NULL)	return SECFailure;    NSS_CMSDigestContext_Update(digcx, input->data, input->len);    return NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests);}static voidUsage(char *progName){    fprintf(stderr, "Usage:  %s [-D|-S|-E] [<options>] [-d dbdir] [-u certusage]\n", progName);    fprintf(stderr, " -i infile     use infile as source of data (default: stdin)\n");    fprintf(stderr, " -o outfile    use outfile as destination of data (default: stdout)\n");    fprintf(stderr, " -d dbdir      key/cert database directory (default: ~/.netscape)\n");    fprintf(stderr, " -p password   use password as key db password (default: prompt)\n");    fprintf(stderr, " -u certusage  set type of certificate usage (default: certUsageEmailSigner)\n");    fprintf(stderr, "\n");    fprintf(stderr, " -D            decode a CMS message\n");    fprintf(stderr, "  -c content   use this detached content\n");    fprintf(stderr, "  -n           suppress output of content\n");    fprintf(stderr, "  -h num       generate email headers with info about CMS message\n");    fprintf(stderr, " -S            create a CMS signed message\n");    fprintf(stderr, "  -N nick      use certificate named \"nick\" for signing\n");    fprintf(stderr, "  -T           do not include content in CMS message\n");    fprintf(stderr, "  -G           include a signing time attribute\n");    fprintf(stderr, "  -P           include a SMIMECapabilities attribute\n");    fprintf(stderr, "  -Y nick      include a EncryptionKeyPreference attribute with cert\n");    fprintf(stderr, " -E            create a CMS enveloped message (NYI)\n");    fprintf(stderr, "  -r id,...    create envelope for these recipients,\n");    fprintf(stderr, "               where id can be a certificate nickname or email address\n");    fprintf(stderr, "\nCert usage codes:\n");    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);}static CERTCertDBHandle certHandleStatic;	/* avoid having to allocate */static CERTCertDBHandle *OpenCertDB(char *progName){    CERTCertDBHandle *certHandle;    SECStatus rv;    certHandle = &certHandleStatic;    rv = CERT_OpenCertDB(certHandle, PR_FALSE, SECU_CertDBNameCallback, NULL);    if (rv != SECSuccess) {        SECU_PrintError(progName, "could not open cert database");	return NULL;    }    return certHandle;}char *ownpw(PK11SlotInfo *info, PRBool retry, void *arg){	char * passwd = NULL;	if ( (!retry) && arg ) {		passwd = PL_strdup((char *)arg);	}	return passwd;}struct optionsStr {    char *password;    SECCertUsage certUsage;    CERTCertDBHandle *certHandle;};struct decodeOptionsStr {    struct optionsStr *options;    PRFileDesc *contentFile;    int headerLevel;    PRBool suppressContent;    NSSCMSGetDecryptKeyCallback dkcb;    PK11SymKey *bulkkey;};struct signOptionsStr {    struct optionsStr *options;    char *nickname;    char *encryptionKeyPreferenceNick;    PRBool signingTime;    PRBool smimeProfile;    PRBool detached;};struct envelopeOptionsStr {    struct optionsStr *options;    char **recipients;};struct certsonlyOptionsStr {    struct optionsStr *options;    char **recipients;};struct encryptOptionsStr {    struct optionsStr *options;    char **recipients;    NSSCMSMessage *envmsg;    SECItem *input;    FILE *outfile;    PRFileDesc *envFile;    PK11SymKey *bulkkey;    SECOidTag bulkalgtag;    int keysize;};static NSSCMSMessage *decode(FILE *out, SECItem *output, SECItem *input,        struct decodeOptionsStr decodeOptions){    NSSCMSDecoderContext *dcx;    NSSCMSMessage *cmsg;    NSSCMSContentInfo *cinfo;    NSSCMSSignedData *sigd = NULL;    NSSCMSEnvelopedData *envd;    NSSCMSEncryptedData *encd;    SECAlgorithmID **digestalgs;    int nlevels, i, nsigners, j;    char *signercn;    NSSCMSSignerInfo *si;    SECOidTag typetag;    SECItem **digests;    PLArenaPool *poolp;    PK11PasswordFunc pwcb;    void *pwcb_arg;    SECItem *item, sitem = { 0, 0, 0 };    pwcb     = (decodeOptions.options->password != NULL) ? ownpw : NULL;    pwcb_arg = (decodeOptions.options->password != NULL) ?                   (void *)decodeOptions.options->password : NULL;    if (decodeOptions.contentFile) {	/* detached content: grab content file */	SECU_FileToItem(&sitem, decodeOptions.contentFile);	item = &sitem;    }    dcx = NSS_CMSDecoder_Start(NULL,                                NULL, NULL,         /* content callback     */                               pwcb, pwcb_arg,     /* password callback    */			       decodeOptions.dkcb, /* decrypt key callback */                               decodeOptions.bulkkey);    (void)NSS_CMSDecoder_Update(dcx, input->data, input->len);    cmsg = NSS_CMSDecoder_Finish(dcx);    if (cmsg == NULL) {	fprintf(stderr, "%s: failed to decode message.\n", progName);	return NULL;    }    if (decodeOptions.headerLevel >= 0) {	/*fprintf(out, "SMIME: ", decodeOptions.headerLevel, i);*/	fprintf(out, "SMIME: ");    }    nlevels = NSS_CMSMessage_ContentLevelCount(cmsg);    for (i = 0; i < nlevels; i++) {	cinfo = NSS_CMSMessage_ContentLevel(cmsg, i);	typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);	if (decodeOptions.headerLevel >= 0)	    fprintf(out, "\tlevel=%d.%d; ", decodeOptions.headerLevel, nlevels - i);	switch (typetag) {	case SEC_OID_PKCS7_SIGNED_DATA:	    if (decodeOptions.headerLevel >= 0)		fprintf(out, "type=signedData; ");	    sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);	    if (sigd == NULL) {		SECU_PrintError(progName, 		                "problem finding signedData component");		goto loser;	    }	    /* if we have a content file, but no digests for this signedData */	    if (decodeOptions.contentFile != NULL && !NSS_CMSSignedData_HasDigests(sigd)) {		if ((poolp = PORT_NewArena(1024)) == NULL) {		    fprintf(stderr, "cmsutil: Out of memory.\n");		    goto loser;		}		digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd);		if (DigestFile (poolp, &digests, item, digestalgs) 		      != SECSuccess) {		    SECU_PrintError(progName, 		                    "problem computing message digest");		    goto loser;		}		if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) {		    		    SECU_PrintError(progName, 		                    "problem setting message digests");		    goto loser;		}		PORT_FreeArena(poolp, PR_FALSE);	    }	    /* import the certificates */	    if (NSS_CMSSignedData_ImportCerts(sigd, 	                                     decodeOptions.options->certHandle, 	                                     decodeOptions.options->certUsage, 	                                     PR_FALSE) 	          != SECSuccess) {		SECU_PrintError(progName, "cert import failed");		goto loser;	    }	    /* find out about signers */	    nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);	    if (decodeOptions.headerLevel >= 0)		fprintf(out, "nsigners=%d; ", nsigners);	    if (nsigners == 0) {		/* must be a cert transport message */		SECStatus rv;		/* XXX workaround for bug #54014 */		NSS_CMSSignedData_ImportCerts(sigd,                                              decodeOptions.options->certHandle, 		                             decodeOptions.options->certUsage, 		                             PR_TRUE);		rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, 		                             decodeOptions.options->certHandle, 		                             decodeOptions.options->certUsage);		if (rv != SECSuccess) {		    fprintf(stderr, "cmsutil: Verify certs-only failed!\n");		    goto loser;		}		return cmsg;	    }	    /* still no digests? */	    if (!NSS_CMSSignedData_HasDigests(sigd)) {		SECU_PrintError(progName, "no message digests");		goto loser;	    }	    for (j = 0; j < nsigners; j++) {		si = NSS_CMSSignedData_GetSignerInfo(sigd, j);		signercn = NSS_CMSSignerInfo_GetSignerCommonName(si);		if (signercn == NULL)		    signercn = "";		if (decodeOptions.headerLevel >= 0)		    fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn);		(void)NSS_CMSSignedData_VerifySignerInfo(sigd, j, 		                             decodeOptions.options->certHandle, 		                             decodeOptions.options->certUsage);		if (decodeOptions.headerLevel >= 0)		    fprintf(out, "signer%d.status=%s; ", j, 		            NSS_CMSUtil_VerificationStatusToString(		                  NSS_CMSSignerInfo_GetVerificationStatus(si)));		    /* XXX what do we do if we don't print headers? */	    }	    break;	case SEC_OID_PKCS7_ENVELOPED_DATA:	    if (decodeOptions.headerLevel >= 0)		fprintf(out, "type=envelopedData; ");	    envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo);	    break;	case SEC_OID_PKCS7_ENCRYPTED_DATA:	    if (decodeOptions.headerLevel >= 0)		fprintf(out, "type=encryptedData; ");	    encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo);	    break;	case SEC_OID_PKCS7_DATA:	    if (decodeOptions.headerLevel >= 0)		fprintf(out, "type=data; ");	    break;	default:	    break;	}	if (decodeOptions.headerLevel >= 0)	    fprintf(out, "\n");    }    if (!decodeOptions.suppressContent) {	if (!decodeOptions.contentFile) 	    item = NSS_CMSMessage_GetContent(cmsg);	SECITEM_CopyItem(NULL, output, item);    }    return cmsg;loser:    if (cmsg)	NSS_CMSMessage_Destroy(cmsg);    return NULL;}/* example of a callback function to use with encoder *//*static voidwriteout(void *arg, const char *buf, unsigned long len){    FILE *f = (FILE *)arg;    if (f != NULL && buf != NULL)	(void)fwrite(buf, len, 1, f);}*/static NSSCMSMessage *signed_data(struct signOptionsStr signOptions){    NSSCMSMessage *cmsg = NULL;    NSSCMSContentInfo *cinfo;    NSSCMSSignedData *sigd;    NSSCMSSignerInfo *signerinfo;    CERTCertificate *cert, *ekpcert;    if (signOptions.nickname == NULL) {	fprintf(stderr,         "ERROR: please indicate the nickname of a certificate to sign with.\n");	return NULL;    }    if ((cert = CERT_FindCertByNickname(signOptions.options->certHandle,                                         signOptions.nickname)) == NULL) {	SECU_PrintError(progName, 	                "the corresponding cert for key \"%s\" does not exist",	                signOptions.nickname);	return NULL;    }    /*     * create the message object     */    cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */    if (cmsg == NULL) {	fprintf(stderr, "ERROR: cannot create CMS message.\n");	return NULL;    }    /*     * build chain of objects: message->signedData->data     */    if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {	fprintf(stderr, "ERROR: cannot create CMS signedData object.\n");	goto loser;    }    cinfo = NSS_CMSMessage_GetContentInfo(cmsg);    if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)           != SECSuccess) {	fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n");	goto loser;    }    cinfo = NSS_CMSSignedData_GetContentInfo(sigd);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?