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 + -
显示快捷键?