p7create.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,321 行 · 第 1/3 页
C
1,321 行
/* * 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. *//* * PKCS7 creation. * * $Id: p7create.c,v 1.1 2000/03/31 19:16:04 relyea%netscape.com Exp $ */#include "p7local.h"#include "cert.h"#include "secasn1.h"#include "secitem.h"#include "secoid.h"#include "secpkcs5.h"#include "pk11func.h"#include "prtime.h"#include "secerr.h"static SECStatussec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PRArenaPool *poolp, SECOidTag kind, PRBool detached){ void *thing; int version; SECItem *versionp; SECStatus rv; PORT_Assert (cinfo != NULL && poolp != NULL); if (cinfo == NULL || poolp == NULL) return SECFailure; cinfo->contentTypeTag = SECOID_FindOIDByTag (kind); PORT_Assert (cinfo->contentTypeTag && cinfo->contentTypeTag->offset == kind); rv = SECITEM_CopyItem (poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid)); if (rv != SECSuccess) return rv; if (detached) return SECSuccess; switch (kind) { default: case SEC_OID_PKCS7_DATA: thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem)); cinfo->content.data = (SECItem*)thing; versionp = NULL; version = -1; break; case SEC_OID_PKCS7_DIGESTED_DATA: thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData)); cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing; versionp = &(cinfo->content.digestedData->version); version = SEC_PKCS7_DIGESTED_DATA_VERSION; break; case SEC_OID_PKCS7_ENCRYPTED_DATA: thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData)); cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing; versionp = &(cinfo->content.encryptedData->version); version = SEC_PKCS7_ENCRYPTED_DATA_VERSION; break; case SEC_OID_PKCS7_ENVELOPED_DATA: thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData)); cinfo->content.envelopedData = (SEC_PKCS7EnvelopedData*)thing; versionp = &(cinfo->content.envelopedData->version); version = SEC_PKCS7_ENVELOPED_DATA_VERSION; break; case SEC_OID_PKCS7_SIGNED_DATA: thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData)); cinfo->content.signedData = (SEC_PKCS7SignedData*)thing; versionp = &(cinfo->content.signedData->version); version = SEC_PKCS7_SIGNED_DATA_VERSION; break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData)); cinfo->content.signedAndEnvelopedData = (SEC_PKCS7SignedAndEnvelopedData*)thing; versionp = &(cinfo->content.signedAndEnvelopedData->version); version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION; break; } if (thing == NULL) return SECFailure; if (versionp != NULL) { SECItem *dummy; PORT_Assert (version >= 0); dummy = SEC_ASN1EncodeInteger (poolp, versionp, version); if (dummy == NULL) return SECFailure; PORT_Assert (dummy == versionp); } return SECSuccess;}static SEC_PKCS7ContentInfo *sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached, SECKEYGetPasswordKey pwfn, void *pwfn_arg){ SEC_PKCS7ContentInfo *cinfo; PRArenaPool *poolp; SECStatus rv; poolp = PORT_NewArena (1024); /* XXX what is right value? */ if (poolp == NULL) return NULL; cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo)); if (cinfo == NULL) { PORT_FreeArena (poolp, PR_FALSE); return NULL; } cinfo->poolp = poolp; cinfo->pwfn = pwfn; cinfo->pwfn_arg = pwfn_arg; cinfo->created = PR_TRUE; cinfo->refCount = 1; rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached); if (rv != SECSuccess) { PORT_FreeArena (poolp, PR_FALSE); return NULL; } return cinfo;}/* * Add a signer to a PKCS7 thing, verifying the signature cert first. * Any error returns SECFailure. * * XXX Right now this only adds the *first* signer. It fails if you try * to add a second one -- this needs to be fixed. */static SECStatussec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo, CERTCertificate * cert, SECCertUsage certusage, CERTCertDBHandle * certdb, SECOidTag digestalgtag, SECItem * digestdata){ SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp; SECAlgorithmID *digestalg, **digestalgs, ***digestalgsp; SECItem *digest, **digests, ***digestsp; SECItem * dummy; void * mark; SECStatus rv; SECOidTag kind; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { case SEC_OID_PKCS7_SIGNED_DATA: { SEC_PKCS7SignedData *sdp; sdp = cinfo->content.signedData; digestalgsp = &(sdp->digestAlgorithms); digestsp = &(sdp->digests); signerinfosp = &(sdp->signerInfos); } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saedp; saedp = cinfo->content.signedAndEnvelopedData; digestalgsp = &(saedp->digestAlgorithms); digestsp = &(saedp->digests); signerinfosp = &(saedp->signerInfos); } break; default: return SECFailure; /* XXX set an error? */ } /* * XXX I think that CERT_VerifyCert should do this if *it* is passed * a NULL database. */ if (certdb == NULL) { certdb = CERT_GetDefaultCertDB(); if (certdb == NULL) return SECFailure; /* XXX set an error? */ } if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(), cinfo->pwfn_arg, NULL) != SECSuccess) { /* XXX Did CERT_VerifyCert set an error? */ return SECFailure; } /* * XXX This is the check that we do not already have a signer. * This is not what we really want -- we want to allow this * and *add* the new signer. */ PORT_Assert (*signerinfosp == NULL && *digestalgsp == NULL && *digestsp == NULL); if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL) return SECFailure; mark = PORT_ArenaMark (cinfo->poolp); signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp, sizeof(SEC_PKCS7SignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version, SEC_PKCS7_SIGNER_INFO_VERSION); if (dummy == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } PORT_Assert (dummy == &signerinfo->version); signerinfo->cert = CERT_DupCertificate (cert); if (signerinfo->cert == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert); if (signerinfo->issuerAndSN == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg, digestalgtag, NULL); if (rv != SECSuccess) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } /* * Okay, now signerinfo is all set. We just need to put it and its * companions (another copy of the digest algorithm, and the digest * itself if given) into the main structure. * * XXX If we are handling more than one signer, the following code * needs to look through the digest algorithms already specified * and see if the same one is there already. If it is, it does not * need to be added again. Also, if it is there *and* the digest * is not null, then the digest given should match the digest already * specified -- if not, that is an error. Finally, the new signerinfo * should be *added* to the set already found. */ signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SEC_PKCS7SignerInfo *)); if (signerinfos == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } signerinfos[0] = signerinfo; signerinfos[1] = NULL; digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID)); digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *)); if (digestalg == NULL || digestalgs == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL); if (rv != SECSuccess) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } digestalgs[0] = digestalg; digestalgs[1] = NULL; if (digestdata != NULL) { digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem)); digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECItem *)); if (digest == NULL || digests == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata); if (rv != SECSuccess) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } digests[0] = digest; digests[1] = NULL; } else { digests = NULL; } *signerinfosp = signerinfos; *digestalgsp = digestalgs; *digestsp = digests; PORT_ArenaUnmark(cinfo->poolp, mark); return SECSuccess;}/* * Helper function for creating an empty signedData. */static SEC_PKCS7ContentInfo *sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg){ SEC_PKCS7ContentInfo *cinfo; SEC_PKCS7SignedData *sigd; SECStatus rv; cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE, pwfn, pwfn_arg); if (cinfo == NULL) return NULL; sigd = cinfo->content.signedData; PORT_Assert (sigd != NULL); /* * XXX Might we want to allow content types other than data? * If so, via what interface? */ rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp, SEC_OID_PKCS7_DATA, PR_TRUE); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } return cinfo;}/* * Start a PKCS7 signing context. * * "cert" is the cert that will be used to sign the data. It will be * checked for validity. * * "certusage" describes the signing usage (e.g. certUsageEmailSigner) * XXX Maybe SECCertUsage should be split so that our caller just says * "email" and *we* add the "signing" part -- otherwise our caller * could be lying about the usage; we do not want to allow encryption * certs for signing or vice versa. * * "certdb" is the cert database to use for verifying the cert. * It can be NULL if a default database is available (like in the client). * * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1). * * "digest" is the actual digest of the data. It must be provided in * the case of detached data or NULL if the content will be included. * * The return value can be passed to functions which add things to * it like attributes, then eventually to SEC_PKCS7Encode() or to * SEC_PKCS7EncoderStart() to create the encoded data, and finally to * SEC_PKCS7DestroyContentInfo(). * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */SEC_PKCS7ContentInfo *SEC_PKCS7CreateSignedData (CERTCertificate *cert, SECCertUsage certusage, CERTCertDBHandle *certdb, SECOidTag digestalg, SECItem *digest, SECKEYGetPasswordKey pwfn, void *pwfn_arg){ SEC_PKCS7ContentInfo *cinfo; SECStatus rv; cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg); if (cinfo == NULL) return NULL; rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb, digestalg, digest); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } return cinfo;}static SEC_PKCS7Attribute *sec_pkcs7_create_attribute (PRArenaPool *poolp, SECOidTag oidtag, SECItem *value, PRBool encoded){ SEC_PKCS7Attribute *attr; SECItem **values; void *mark;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?