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