cmssiginfo.c

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

C
872
字号
/* * 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. *//* * CMS signerInfo methods. * * $Id: cmssiginfo.c,v 1.4 2000/06/20 16:28:57 chrisk%netscape.com Exp $ */#include "cmslocal.h"#include "cert.h"#include "key.h"#include "secasn1.h"#include "secitem.h"#include "secoid.h"#include "pk11func.h"#include "prtime.h"#include "secerr.h"#include "cryptohi.h"#include "smime.h"/* ============================================================================= * SIGNERINFO */NSSCMSSignerInfo *NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag){    void *mark;    NSSCMSSignerInfo *signerinfo;    int version;    PLArenaPool *poolp;    poolp = cmsg->poolp;    mark = PORT_ArenaMark(poolp);    signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));    if (signerinfo == NULL) {	PORT_ArenaRelease(poolp, mark);	return NULL;    }    if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)	goto loser;    signerinfo->cmsg = cmsg;    signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;	/* hardcoded for now */    if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)	goto loser;    /* set version right now */    version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;    /* RFC2630 5.3 "version is the syntax version number. If the .... " */    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)	version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)	goto loser;    PORT_ArenaUnmark(poolp, mark);    return signerinfo;loser:    PORT_ArenaRelease(poolp, mark);    return NULL;}/* * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure */voidNSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si){    if (si->cert != NULL)	CERT_DestroyCertificate(si->cert);    /* XXX storage ??? */}/* * NSS_CMSSignerInfo_Sign - sign something * */SECStatusNSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType){    CERTCertificate *cert;    SECKEYPrivateKey *privkey = NULL;    SECOidTag digestalgtag;    SECOidTag signalgtag;    SECItem signature = { 0 };    SECStatus rv;    PLArenaPool *poolp, *tmppoolp;     PORT_Assert (digest != NULL);    poolp = signerinfo->cmsg->poolp;    cert = signerinfo->cert;    if ((privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg)) == NULL)	goto loser;    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);    /*     * XXX I think there should be a cert-level interface for this,     * so that I do not have to know about subjectPublicKeyInfo...     */    signalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));    /* Fortezza MISSI have weird signature formats.  Map them to standard DSA formats */    signalgtag = PK11_FortezzaMapSig(signalgtag);    if (signerinfo->authAttr != NULL) {	SECItem encoded_attrs;	/* find and fill in the message digest attribute. */	rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);	if (rv != SECSuccess)	    goto loser;	if (contentType != NULL) {	    /* if the caller wants us to, find and fill in the content type attribute. */	    rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);	    if (rv != SECSuccess)		goto loser;	}	if ((tmppoolp = PORT_NewArena (1024)) == NULL) {	    PORT_SetError(SEC_ERROR_NO_MEMORY);	    goto loser;	}	/*	 * Before encoding, reorder the attributes so that when they	 * are encoded, they will be conforming DER, which is required	 * to have a specific order and that is what must be used for	 * the hash/signature.  We do this here, rather than building	 * it into EncodeAttributes, because we do not want to do	 * such reordering on incoming messages (which also uses	 * EncodeAttributes) or our old signatures (and other "broken"	 * implementations) will not verify.  So, we want to guarantee	 * that we send out good DER encodings of attributes, but not	 * to expect to receive them.	 */	if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)	    goto loser;	encoded_attrs.data = NULL;	encoded_attrs.len = 0;	if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL)	    goto loser;	rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, privkey,			   NSS_CMSUtil_MakeSignatureAlgorithm(digestalgtag, signalgtag));	PORT_FreeArena(tmppoolp, PR_FALSE);	/* awkward memory management :-( */    } else {	rv = SGN_Digest(privkey, digestalgtag, &signature, digest);    }    SECKEY_DestroyPrivateKey(privkey);    privkey = NULL;    if (rv != SECSuccess)	goto loser;    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess)	goto loser;    SECITEM_FreeItem(&signature, PR_FALSE);    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), signalgtag, NULL) != SECSuccess)	goto loser;    return SECSuccess;loser:    if (signature.len != 0)	SECITEM_FreeItem (&signature, PR_FALSE);    if (privkey)	SECKEY_DestroyPrivateKey(privkey);    return SECFailure;}SECStatusNSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,			    SECCertUsage certusage){    CERTCertificate *cert;    int64 stime;    if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {	signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;	return SECFailure;    }    /*     * Get and convert the signing time; if available, it will be used     * both on the cert verification and for importing the sender     * email profile.     */    if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess)	stime = PR_Now();	/* not found or conversion failed, so check against now */        /*     * XXX  This uses the signing time, if available.  Additionally, we     * might want to, if there is no signing time, get the message time     * from the mail header itself, and use that.  That would require     * a change to our interface though, and for S/MIME callers to pass     * in a time (and for non-S/MIME callers to pass in nothing, or     * maybe make them pass in the current time, always?).     */    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime, signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {	signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;	return SECFailure;    }    return SECSuccess;}/* * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo * * Just verifies the signature. The assumption is that verification of the certificate * is done already. */SECStatusNSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType){    SECKEYPublicKey *publickey = NULL;    NSSCMSAttribute *attr;    SECItem encoded_attrs;    CERTCertificate *cert;    NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;    PLArenaPool *poolp;    if (signerinfo == NULL)	return SECFailure;    /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL and */    /* cert has not been verified */    if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL)) == NULL) {	vs = NSSCMSVS_SigningCertNotFound;	goto loser;    }    if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {	vs = NSSCMSVS_ProcessingError;	goto loser;    }    /*     * XXX This may not be the right set of algorithms to check.     * I'd prefer to trust that just calling VFY_Verify{Data,Digest}     * would do the right thing (and set an error if it could not);     * then additional algorithms could be handled by that code     * and we would Just Work.  So this check should just be removed,     * but not until the VFY code is better at setting errors.     */    switch (SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg))) {    case SEC_OID_PKCS1_RSA_ENCRYPTION:    case SEC_OID_ANSIX9_DSA_SIGNATURE:    case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:	/* ok */	break;    case SEC_OID_UNKNOWN:	vs = NSSCMSVS_SignatureAlgorithmUnknown;	goto loser;    default:	vs = NSSCMSVS_SignatureAlgorithmUnsupported;	goto loser;    }    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {	if (contentType) {	    /*	     * Check content type	     *	     * RFC2630 sez that if there are any authenticated attributes,	     * then there must be one for content type which matches the	     * content type of the content being signed, and there must	     * be one for message digest which matches our message digest.	     * So check these things first.	     */	    if ((attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,					SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL)	    {		vs = NSSCMSVS_MalformedSignature;		goto loser;	    }			    if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {		vs = NSSCMSVS_MalformedSignature;		goto loser;	    }	}	/*	 * Check digest	 */	if ((attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL)	{	    vs = NSSCMSVS_MalformedSignature;	    goto loser;	}	if (NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {	    vs = NSSCMSVS_DigestMismatch;	    goto loser;	}	if ((poolp = PORT_NewArena (1024)) == NULL) {	    vs = NSSCMSVS_ProcessingError;	    goto loser;	}	/*	 * Check signature	 *	 * The signature is based on a digest of the DER-encoded authenticated	 * attributes.  So, first we encode and then we digest/verify.	 * we trust the decoder to have the attributes in the right (sorted) order	 */	encoded_attrs.data = NULL;	encoded_attrs.len = 0;	if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL ||		encoded_attrs.data == NULL || encoded_attrs.len == 0)	{	    vs = NSSCMSVS_ProcessingError;	    goto loser;	}	vs = (VFY_VerifyData (encoded_attrs.data, encoded_attrs.len,			publickey, &(signerinfo->encDigest),			SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)),			signerinfo->cmsg->pwfn_arg) != SECSuccess) ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;	PORT_FreeArena(poolp, PR_FALSE);	/* awkward memory management :-( */    } else {	SECItem *sig;	/* No authenticated attributes. The signature is based on the plain message digest. */	sig = &(signerinfo->encDigest);	if (sig->len == 0)	    goto loser;	vs = (VFY_VerifyDigest(digest, publickey, sig,			SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)),			signerinfo->cmsg->pwfn_arg) != SECSuccess) ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;    }    if (vs == NSSCMSVS_BadSignature) {	/*	 * XXX Change the generic error into our specific one, because	 * in that case we get a better explanation out of the Security	 * Advisor.  This is really a bug in our error strings (the	 * "generic" error has a lousy/wrong message associated with it	 * which assumes the signature verification was done for the	 * purposes of checking the issuer signature on a certificate)	 * but this is at least an easy workaround and/or in the	 * Security Advisor, which specifically checks for the error	 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation	 * in that case but does not similarly check for	 * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would	 * probably say the wrong thing in the case that it *was* the	 * certificate signature check that failed during the cert	 * verification done above.  Our error handling is really a mess.	 */	if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)	    PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);    }    if (publickey != NULL)	SECKEY_DestroyPublicKey (publickey);    signerinfo->verificationStatus = vs;    return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;loser:    if (publickey != NULL)	SECKEY_DestroyPublicKey (publickey);    signerinfo->verificationStatus = vs;    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);    return SECFailure;}NSSCMSVerificationStatusNSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo){    return signerinfo->verificationStatus;}SECOidData *NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo){    return SECOID_FindOID (&(signerinfo->digestAlg.algorithm));}

⌨️ 快捷键说明

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